Skip to main content

SF-9005 · Compare · Medium

What is the difference between @wire and imperative Apex calls in LWC?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

LWC gives you two ways to call Apex from a component: the @wire decorator and imperative invocation. They look similar at first glance, but they solve very different problems.

The reactive way — @wire

public with sharing class ContactController {
    @AuraEnabled(cacheable=true)
    public static List<Contact> findByAccount(Id accountId) {
        return [SELECT Id, Name, Email FROM Contact WHERE AccountId = :accountId];
    }
}
import { LightningElement, api, wire } from 'lwc';
import findByAccount from '@salesforce/apex/ContactController.findByAccount';

export default class ContactList extends LightningElement {
    @api accountId;

    @wire(findByAccount, { accountId: '$accountId' })
    contacts;   // { data, error }

    get rows()  { return this.contacts?.data ?? []; }
    get error() { return this.contacts?.error; }
}

What you get:

  • The wire fires automatically on first render.
  • It re-fires whenever $accountId changes (the $ makes it reactive).
  • The result is cached by the Lightning Data Service, so two components asking for the same data share one network round-trip.
  • The Apex method must be @AuraEnabled(cacheable=true) — the cache contract requires the method to be free of side effects.

The on-demand way — imperative

public with sharing class ContactController {
    @AuraEnabled
    public static Contact upsertContact(Contact c) {
        upsert c;
        return c;
    }
}
import { LightningElement } from 'lwc';
import upsertContact from '@salesforce/apex/ContactController.upsertContact';

export default class ContactForm extends LightningElement {
    contact = { FirstName: '', LastName: '', Email: '' };
    isSaving = false;

    async handleSave() {
        this.isSaving = true;
        try {
            const saved = await upsertContact({ c: this.contact });
            this.dispatchEvent(new CustomEvent('saved', { detail: saved }));
        } catch (err) {
            this.error = err.body?.message ?? 'Save failed';
        } finally {
            this.isSaving = false;
        }
    }
}

What you get:

  • Full control over when the call happens — on click, on timer, on validation pass.
  • A returned Promise you can await and try/catch.
  • The ability to call non-cacheable methods, which is mandatory for any DML.

Side-by-side

@wireImperative
When does it fire?Framework decides (initial + reactive deps)You decide
Apex annotation@AuraEnabled(cacheable=true) required@AuraEnabled (cacheable optional)
Side effects allowed?No — must be read-onlyYes — DML, callouts, anything
CachingAutomatic via Lightning Data ServiceNone (write your own if needed)
Refresh APIrefreshApex(wiredVar)Just call the function again
Error handlingInspect .error propertytry/catch or .catch()
Reactive parametersYes ('$prop')No — pass values explicitly

When to choose which

Use @wire when:

  • You need to read data on render or in reaction to parameter changes.
  • You want caching and refresh with minimal code.
  • The data is genuinely side-effect-free (queries, describe calls, custom-metadata reads).

Use imperative when:

  • You’re performing CRUD — insert, update, delete.
  • The call must be conditional (only fire after a user action).
  • You need error handling control beyond inspecting an .error property.
  • You want to chain calls (await getA(); await getB(prevResult)).

Refreshing wired data after an imperative write

A classic interview question. The pattern:

import { refreshApex } from '@salesforce/apex';

@wire(findByAccount, { accountId: '$accountId' })
wiredContacts;   // bind to a variable so we can refresh it

async handleSave() {
    await upsertContact({ c: this.contact });
    await refreshApex(this.wiredContacts);  // re-fetch the wire's data
}

refreshApex invalidates the LDS cache entry and re-runs the wire. Without it, your wire will keep serving stale cached data after a write.

Verified against: LWC Developer Guide — Call Apex Methods, Wire Service. Last reviewed 2026-05-17 for Spring ‘26 release.