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

# Function Active Limits

> Per-shop active-install caps per function type and how to manage them

# Function Active Limits

LaunchMyStore caps how many **actively-installed** apps a single shop
can have running per function type. The cap is enforced at install
time — if installing your app would push the merchant over the limit
for any of the function types it ships, the install fails with
HTTP 409.

## Why the caps exist

Every active function of a given type is dispatched on every
cart verification and order placement call. Without an upper bound, a
shop could:

* **Compound discounts** unbounded — 50 active discount functions all
  emitting overlapping reductions on the same lines, blowing through
  the merchant's margin.
* **Stack payment customizations** that rename or hide the same method
  in conflicting ways, producing UI that flickers as each function's
  override fires.
* **Run order validation rules** that each adds latency to checkout;
  ten 500-ms WASM modules add 5 seconds to every checkout submit.
* **Multiply WASM CPU cost** for cart-transform pipelines that compete
  for the same line ids.

The caps are deliberately conservative for the high-impact types
(`cart_transform`, `order_validation`) and generous for low-cost,
additive types (`discount`).

## Per-type limits

These caps are defined in `FUNCTION_ACTIVE_LIMITS` in the backend
`apps/functions/function-contracts.ts` and applied by
`apps.service.installApp()`.

| Function type             | Active cap | Rationale                                                                                                                                                                        |
| ------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cart_transform`          | **1**      | Cart transforms can merge/expand lines; multiple transforms ordering across each other is non-deterministic. One active app at a time keeps the pipeline predictable.            |
| `discount`                | **25**     | Discounts are additive and applied through the documented `discountApplicationStrategy` (FIRST / MAXIMUM / ALL); merchants commonly stack many automatic + code-based discounts. |
| `shipping_rate`           | 5          | Each function adds rates to the same option list — too many makes checkout cluttered.                                                                                            |
| `payment_customization`   | 5          | Renames, hides, and reorders compose, but conflicts (two apps renaming the same method) produce undefined order.                                                                 |
| `delivery_customization`  | 5          | Same composition concerns as payment customization.                                                                                                                              |
| `order_validation`        | 5          | Validation runs on every cart change and order submit — latency is multiplicative.                                                                                               |
| `fulfillment_constraints` | 5          | Intersected per line; more functions means smaller allowed-location sets and a higher risk of unfulfillable orders.                                                              |
| `local_pickup_options`    | 5          | All pickup options are merged into one customer-facing list.                                                                                                                     |
| `pickup_point_options`    | 5          | Same merge semantics as local pickup.                                                                                                                                            |

<Note>
  Caps apply to **active** installs only. Installing an app, then
  disabling its functions (uninstall, suspend, or developer-side
  toggle) frees the slot for another app of the same type.
</Note>

## What "active install" means

A function counts toward the cap when **all** of these are true for an
app installed on the shop:

1. The app's installation row has `status = 'active'` (not
   `uninstalled`, `suspended`, or `pending`).
2. The function entry exists in the installed version's manifest.
3. The function hasn't been disabled by the merchant (per-function
   toggle in admin).

Apps in `draft` or `review` status on the developer dashboard don't
count — only published apps installed on a merchant's shop.

## Hitting the cap

When a merchant tries to install an app that would push them over the
cap for any function type the app contributes, the backend returns:

```http theme={null}
HTTP/1.1 409 Conflict
Content-Type: application/json

{
  "error": "Conflict",
  "message": "Function active limit exceeded: cart_transform (1/1)",
  "code": "FUNCTION_ACTIVE_LIMIT_EXCEEDED",
  "details": {
    "functionType": "cart_transform",
    "limit": 1,
    "current": 1
  }
}
```

The merchant admin shows this as an inline error on the marketplace
install button: *"You've reached the limit for this function type.
Disable another app first."*

## Freeing up a slot

Merchants have three ways to free a slot for a competing app:

<Steps>
  <Step title="Uninstall a competing app">
    Removes the app entirely. Slot frees immediately.
  </Step>

  <Step title="Disable the specific function">
    Some apps expose per-function toggles in their admin UI. Disabling
    a function de-activates that one slot without removing the app.
  </Step>

  <Step title="Switch to a unified app">
    If two apps each contribute one `cart_transform`, the merchant
    can switch to a single bundled app that performs both transforms
    in one function — using the cap of 1 just once.
  </Step>
</Steps>

## Edge cases

<AccordionGroup>
  <Accordion title="Multi-function apps">
    An app that contributes a `cart_transform` AND a `discount`
    function consumes one slot from each cap. Installing it requires
    both caps to have headroom — it'll fail with 409 even if only one
    is full.
  </Accordion>

  <Accordion title="Reinstall a previously-uninstalled app">
    Uninstalling sets the installation row to inactive; the slot frees
    immediately. Reinstalling counts the same as a fresh install for
    cap purposes.
  </Accordion>

  <Accordion title="App version updates">
    Updating an installed app to a new version that adds a new function
    type re-checks the cap for that type. If full, the update fails
    with 409 and the previous version stays active.
  </Accordion>

  <Accordion title="Developer staging stores">
    Caps apply per shop, including the developer's own dev shop. A
    developer testing 10 discount-function variants in one shop must
    uninstall some between iterations or stay under 25 active installs.
  </Accordion>

  <Accordion title="What about fulfillment_location_rule?">
    Order-routing rules dispatched as type `fulfillment_location_rule`
    are JSON matchers — not WASM functions — and don't count toward
    any cap. See [Order Routing](/extensions/order-routing).
  </Accordion>
</AccordionGroup>

## Designing within the caps

If you're publishing an app that ships any function, design with the
caps in mind:

* **Bundle related logic** into one function where possible. One
  `discount` function that picks the right rule based on cart contents
  beats five thin functions each gated on its own condition.
* **Use `inputFields`** so your function dispatches faster and is less
  likely to be cited by merchants as "the slow one." See
  [Input fields](/functions/input-fields).
* **Document the cap** in your marketplace listing if your app
  contributes a `cart_transform` — merchants can have only one such
  app and need to know before committing.
* **Surface conflicts**. If your discount function produces
  surprising results when another app is also installed, log a
  warning to the developer dashboard via the test endpoint.

## See also

<CardGroup cols={2}>
  <Card title="Functions Overview" icon="bolt" href="/functions/overview">
    The nine function types and what each one does.
  </Card>

  <Card title="Input fields" icon="filter" href="/functions/input-fields">
    Reduce dispatch cost by projecting the input down to only the
    fields your function reads.
  </Card>

  <Card title="App Manifest" icon="file-code" href="/getting-started/app-manifest#functions">
    Manifest fields for declaring functions.
  </Card>

  <Card title="App Tiers" icon="layer-group" href="/getting-started/app-types-and-tiers">
    Tier-based API rate limits run alongside the function caps.
  </Card>
</CardGroup>
