> For the complete documentation index, see [llms.txt](https://triton.pharos.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://triton.pharos.ai/beyond-apex/lwc-and-apex-cache.md).

# Platform Cache for Transactions

Use Salesforce Platform Cache to share a transaction id across contexts — correlate LWC and Apex logs without passing the id by hand.

[LWC and Apex](/beyond-apex/lwc-and-apex.md) threaded the transaction id through a method parameter. That's clean when you control the call and there's an obvious place to put it. But sometimes there isn't — multiple components, async hops, a chain of calls where plumbing an id through every signature is a pain. For those cases, Platform Cache can hold the id for you, and both sides just ask for it.

{% hint style="info" %}
**Prerequisite:** you need a default cache partition with an Org cache allocation. See [Platform Cache Setup](/installing-pharos-triton.md#platform-cache-setup) in the install guide.
{% endhint %}

## The idea

Instead of passing the id, you call `withCache()`. Triton stores the transaction id in Platform Cache keyed by the running user, and any other context that calls `withCache()` for the same user picks it up. No parameter required.

## LWC side

Notice there's **no `transactionId` argument** — the component just flags that caching is on:

{% code title="logDemo.js" lineNumbers="true" %}

```javascript
export default class LogDemo extends LightningElement {
    triton;

    connectedCallback() {
        this.triton = new Triton().bindToComponent('LogDemo');
    }

    async executeScenario() {
        await this.triton.logNow(
            this.triton.debug(TYPE.FRONTEND, AREA.ACCOUNTS)
                .summary('Cache Demo - Start')
                .details('Starting execution with cache enabled')
        );

        try {
            // No transactionId passed — the cache carries it
            await apexActionThatGeneratesDMLError({ cacheEnabled: true });
        } catch (error) {
            await this.triton.logNow(this.triton.exception(error));
        }
    }
}
```

{% endcode %}

## Apex side

One call — `Triton.withCache()` — and the Apex logs adopt the cached transaction id:

{% code title="LogDemoController.cls" lineNumbers="true" %}

```apex
public with sharing class LogDemoController {
    @AuraEnabled
    public static void apexActionThatGeneratesDMLError(Boolean cacheEnabled) {
        if (cacheEnabled) {
            Triton.withCache();   // resume the cached transaction id (or start one)
        }

        Triton.debug(Triton.t
            .type(TritonTypes.Type.Backend)
            .area(TritonTypes.Area.Community)
            .summary('Cache Demo - Apex')
            .details('Executing with cached transaction id'));

        try {
            ContentVersion cv = new ContentVersion();
            cv.ContentLocation = 'Apex Error';
            cv.Title = 'Apex Error';
            cv.PathOnClient = 'ApexError.pdf';
            insert cv;
        } catch (Exception e) {
            Triton.error(Triton.t.area(TritonTypes.Area.Community).exception(e));
        }

        Triton.flush();
    }
}
```

{% endcode %}

## How `withCache()` works

When you call it, Triton runs this logic:

1. Check whether Platform Cache is available and configured.
2. **If it is:** build a cache key from the running user's id, look for an existing transaction id, **resume** it if found, or **start** a new one and cache it if not.
3. **If it isn't:** fall back to starting a normal transaction and carry on.

That automatic fallback is the nice part — you never have to special-case an org without cache configured. `withCache()` just does the right thing.

## When to use it — and when not to

### Good fits

* Multiple components or services that should share one trace.
* Correlating across asynchronous boundaries where parameter passing is awkward.
* Reducing signature clutter in a deep call chain.

### Caveats

{% hint style="warning" %}
The cache key is the **running user's id**, so every operation that user performs within the cache window shares one transaction id. That can group things you didn't mean to group:

1. A batch job running as the same user who triggered an LWC action.
2. Multiple browser tabs doing similar work at once.
3. Cache that isn't cleared between logically separate operations.

When separation matters, prefer explicit parameter passing — or call `Triton.startTransaction()` to force a fresh id.
{% endhint %}

### Won't work with cacheable Apex / `@wire`

{% hint style="warning" %}
`@AuraEnabled(Cacheable=true)` methods are read-only for Platform Cache — cache writes are inaccessible. That means `Triton.withCache()` cannot store or resume a transaction id inside a cacheable method.

For `@wire` (and any other cacheable Apex), preserve transaction stitching by passing `transactionId` explicitly and calling `Triton.resumeTransaction(transactionId)` on the server. See the worked example in [With `@wire`](/beyond-apex/lwc-and-apex.md#with-wire) on the previous page.
{% endhint %}

### Rules of thumb

* Use **parameter passing** for simple, synchronous, single-hop calls (the [previous page](/beyond-apex/lwc-and-apex.md)).
* Use **parameter passing** for cacheable Apex / `@wire` — do not rely on `withCache()` there.
* Use **cache** for genuinely complex, multi-context scenarios where signatures are awkward **and** the Apex is not cacheable.
* Reach for `startTransaction()` when you need a clean boundary between operations.

Platform cache is a sharp tool — powerful for the hard cases, overkill for the easy ones. Pick based on how tangled your call graph actually is. For the bigger picture on stitching traces across every layer, see [Transactions & Cache](/end-to-end/transactions-and-cache.md) and [End-to-End Logging](/end-to-end.md).
