> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usecharlie.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Backlog Routing

> Prioritize locations with shorter open backlogs and optionally block locations that are overwhelmed

Backlog routing ranks locations by how many open fulfillment orders they have, sending new orders toward locations with shorter queues. Optionally, you can also block a location once its backlog grows past a maximum threshold.

<Info>
  Backlog routing has two modes:

  * **Prefer other locations** — soft signal that ranks locations with shorter backlogs higher (a routing rule)
  * **Block orders** — hard cap that excludes a location entirely once its backlog crosses the threshold (a fulfillment constraint)

  Both are configured from the same place per location.
</Info>

## How backlog routing works

Charlie tracks the **count of unfulfilled fulfillment orders** assigned to each location and exposes it as a public metafield. The Backlog location rule ranks locations in two tiers:

```
No backlog limit set → Always top rank
Backlog limit set → Ranked by % of that location's own threshold still free
```

```mermaid theme={"system"}
flowchart TD
    A[Order placed] --> B{Backlog limit<br/>set at this location?}
    B -->|No| C[Top tier — always tried first]
    B -->|Yes| D[Rank by % of own<br/>threshold still free]
    D --> E[Warehouse: 100 limit, 20 pending → 80% free]
    D --> F[Store Lyon: 50 limit, 30 pending → 40% free]
    D --> G[Store Paris: 20 limit, 15 pending → 25% free]
    C --> H[Try no-limit locations first,<br/>then Warehouse, then Lyon, then Paris]
```

Locations that haven't opted in (via the **Backlog limit** toggle on their Shipping tab) always rank above every location that has a backlog limit configured — they're treated as having no backlog pressure at all, not left neutral for other rules to decide.

<Note>
  By default the backlog count includes every **pending** fulfillment order assigned to the location — both **Open** (accepted, nothing fulfilled yet) and **In progress** (partially fulfilled). Closed and cancelled orders never count. You can narrow this to only **In progress** orders — see [What counts toward backlog](#what-counts-toward-backlog) below. The count refreshes as orders are created, fulfilled, moved, cancelled, un-fulfilled, held, released, or rescheduled.
</Note>

## What counts toward backlog

By default a location's backlog counts every **pending** fulfillment order — both **Open** and **In progress**. You can change what counts from **Charlie → Settings → Backlog**.

| Option                           | What it counts                                                | When to use it                                                                                                         |
| -------------------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **All pending orders** (default) | Open + In progress — every unfulfilled order at the location  | Backlog should reflect the full pipeline waiting at the location                                                       |
| **Only orders in progress**      | In progress only — orders you have already started fulfilling | Accepted orders you haven't begun (for example, waiting on a prescription or a back-order) shouldn't inflate the count |

<Note>
  This is a shop-wide setting that applies to every location's backlog count, in both **Prefer** and **Block** modes. It doesn't require any change to your order routing rules — the same `backlog_count` metafield is recomputed under the new definition.
</Note>

## Setup overview

Backlog routing requires two steps:

1. **Configure backlog limits per location** in Charlie
2. **Add the Backlog location rule** in Shopify Order Routing

## Step 1: Configure backlog per location

<Steps>
  <Step title="Open a location">
    Go to **Charlie → Locations** and select the location you want to configure.
  </Step>

  <Step title="Navigate to Shipping settings">
    Click the **Shipping** tab.
  </Step>

  <Step title="Enable Backlog limit">
    In the **Shipping constraints** section, toggle on **Backlog limit**.
  </Step>

  <Step title="Set the threshold and mode">
    Configure the backlog settings:

    | Field                      | Description                                                                                                  |
    | -------------------------- | ------------------------------------------------------------------------------------------------------------ |
    | **Maximum pending orders** | The threshold. For BLOCK mode, the location stops accepting once it reaches this number. Range: 1 to 25,000. |
    | **How to handle backlog**  | Choose between **Prefer other locations** (soft) or **Block orders** (hard).                                 |
  </Step>

  <Step title="Repeat per location">
    Configure backlog settings for each location you want to include.
  </Step>
</Steps>

### Backlog modes

| Mode                       | Behavior                                                                                                                         |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| **Prefer other locations** | Soft signal. The location with fewer pending orders is ranked higher. If it's the only option, it can still fulfill.             |
| **Block orders**           | Hard cap. Once the location's backlog reaches the threshold, it's excluded entirely until the backlog drops below the threshold. |

<Tip>
  Use **Prefer other locations** for load balancing across multiple locations. Use **Block orders** when a location genuinely cannot handle more pending orders — for example, a small store with a strict 50-order pipeline.
</Tip>

## Step 2: Add the routing rule in Shopify

The **Backlog location rule** must be installed in Shopify's Order Routing for the soft signal to take effect.

<Steps>
  <Step title="Open Order routing">
    Go to **Charlie → Settings → Order routing** or **Shopify → Settings → Shipping and delivery → Order routing**.
  </Step>

  <Step title="Add the Backlog location rule">
    Find Charlie's **Backlog location rule** in the available rules list and add it to your routing strategy.
  </Step>

  <Step title="Enable the rule">
    Toggle the rule to **Enabled**. The rule will use the backlog thresholds and modes you configured per location.
  </Step>
</Steps>

<Note>
  Charlie shows a reminder banner on the location's Shipping tab when **Prefer other locations** mode is enabled but the Backlog location rule isn't installed yet. Click **Manage order routing** in the banner to jump to the settings.
</Note>

### Block mode and the routing rule

If you only ever use **Block orders** mode, you don't strictly need to install the Backlog location rule — the hard block is enforced as a fulfillment constraint independently. The routing rule only matters for the soft "prefer" signal.

## How ranking works

### No-limit locations rank first

Any location without a backlog limit enabled ranks above every location that has one — regardless of how many pending orders it actually has. This is the top tier; a location can only rank below it by having a backlog limit configured.

### Ranked by free capacity, not raw count

Among locations with a backlog limit set to **Prefer other locations**, ranking is based on the percentage of that location's own threshold still free — not the raw number of pending orders. A location with a small threshold that's nearly full ranks below a busier location that still has plenty of room relative to its own limit.

| Location    | Backlog limit | Pending orders | Free capacity | Rank     |
| ----------- | ------------- | -------------- | ------------- | -------- |
| Store Nice  | *(not set)*   | 40             | —             | 1 (top)  |
| Warehouse A | 100           | 20             | 80% free      | 2        |
| Store Lyon  | 50            | 30             | 40% free      | 3        |
| Store Paris | 20            | 15             | 25% free      | 4 (last) |

Notice Store Nice ranks first with the *most* pending orders, because it has no backlog limit set. And Store Paris ranks last despite having the *fewest* pending orders, because it's the closest to its own (small) threshold.

### Tie-breaking

Free capacity is compared in 5% bands rather than exact percentages, so locations that land in the same band share a rank. Shopify then uses its default logic to choose between tied locations.

## Example scenarios

### Balance fulfillment across stores

**Problem:** Your Paris store has a much longer pipeline than the others and shipments are slipping.

**Setup:**

* All stores: Backlog limit enabled, threshold 100, mode = Prefer other locations

**Result:** Orders prefer the store with the shortest current backlog. Paris naturally catches up as the others take more orders.

***

### Hard block a small store at peak

**Problem:** A small store can only physically process 30 open pickup orders at once. Beyond that, orders pile up and customers complain.

**Setup:**

* Small store: Backlog limit enabled, threshold 30, mode = Block orders

**Result:** Once the store has 30 open fulfillment orders, it's excluded from new assignments until enough orders are fulfilled or moved away.

***

### Combine prefer and block across the network

**Problem:** Across 10 stores, you want to load-balance most of the time, but a couple of stores are extra-constrained.

**Setup:**

* 8 stores: Backlog limit enabled, threshold 200, mode = Prefer other locations
* 2 small stores: Backlog limit enabled, threshold 50, mode = Block orders

**Result:** The big network is balanced softly, and the two small stores are protected from spilling over.

## Combining with other rules

### With Inventory Rules

Prefer locations with both stock AND short backlogs:

1. **Inventory Rules** — Rank by available stock
2. **Backlog routing** — Among in-stock locations, prefer those with shorter backlogs

**Result:** Orders go to locations that have both the inventory and the capacity to fulfill promptly.

### With Capacity Rules

Backlog and daily order limit serve different windows:

| Signal       | Window        | Question                                       |
| ------------ | ------------- | ---------------------------------------------- |
| **Capacity** | Today         | How many orders has this location taken today? |
| **Backlog**  | All-time open | How many orders are still unfulfilled here?    |

Use both to combine "what's been assigned today" with "what's still in the pipeline."

### With Ranked Location Groups

Use backlog as a secondary factor within groups:

1. **Ranked Location Groups** — Warehouses (Group 1) → Stores (Group 2)
2. **Backlog routing** — Within each group, prefer locations with shorter backlogs

## Public metafields

Backlog data is exposed on each location as public metafields so other apps and your storefront can read it:

| Metafield                                  | Type            | Description                                                                               |
| ------------------------------------------ | --------------- | ----------------------------------------------------------------------------------------- |
| `$app:location.backlog_count`              | number\_integer | Current count of open fulfillment orders                                                  |
| `$app:location.backlog_blocked`            | boolean         | `true` when the location is over its threshold in BLOCK mode                              |
| `$app:location.backlog_preference_enabled` | boolean         | `true` when the location has opted into the PREFER signal                                 |
| `$app:location.backlog_quota_left_ratio`   | number\_decimal | Fraction of backlog capacity still free (0.0 to 1.0) — what PREFER mode actually ranks on |

The same data is mirrored in the public `charlie_location` namespace for storefront access.

## Best practices

<CardGroup cols={2}>
  <Card title="Start with Prefer mode" icon="play">
    Begin with **Prefer other locations** to softly balance load. Move to Block only for locations that need a hard cap.
  </Card>

  <Card title="Tune thresholds gradually" icon="sliders">
    Start with generous thresholds and tighten over time as you learn each location's real capacity.
  </Card>

  <Card title="Combine with capacity rules" icon="layer-group">
    Pair backlog (open pipeline) with daily order limit (today's intake) for fuller picture of location load.
  </Card>

  <Card title="Monitor metafield values" icon="chart-line">
    The `backlog_count` metafield exposes live counts — use it in dashboards or external monitoring.
  </Card>
</CardGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Orders not shifting toward locations with shorter backlogs">
    **Check:**

    1. Is the **Backlog location rule** enabled in Shopify Order Routing?
    2. Is **Backlog limit** enabled and set to **Prefer other locations** at the locations you want to balance?
    3. Are the locations' `backlog_count` metafields actually different? Check via the Shopify admin metafields panel.
    4. Are there higher-priority rules above the Backlog rule that override its ranking?
  </Accordion>

  <Accordion title="Location blocked unexpectedly">
    **Check:**

    1. Is **Backlog limit** set to **Block orders**?
    2. Has the location's open backlog crossed the threshold?
    3. The block lifts automatically once the backlog drops below the threshold — no manual action needed.
  </Accordion>

  <Accordion title="Backlog count seems wrong">
    **Check:**

    1. The count includes the statuses chosen in **Settings → Backlog** — by default Open and In progress. If you switched to **Only orders in progress**, accepted-but-not-started orders won't be counted.
    2. The count refreshes from webhook events (order created, fulfilled, cancelled, un-fulfilled, moved, split, merged, held, released, or rescheduled) and may take a few seconds to propagate.
    3. If the count seems stuck, contact support to trigger a manual recompute.
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Capacity Rules" icon="gauge-high" href="/order-routing/capacity-rules">
    Daily order limit per location
  </Card>

  <Card title="Order routing overview" icon="memo-circle-info" href="/order-routing/overview">
    All available routing rules
  </Card>

  <Card title="Inventory Rules" icon="warehouse" href="/order-routing/inventory-rules">
    Prioritize locations with more stock
  </Card>

  <Card title="Ranked Location Groups" icon="layer-group" href="/order-routing/ranked-location-groups">
    Primary location preference groups
  </Card>
</CardGroup>
