@wire(getRecord, ...) requires the fields property
You used `getRecord` from `lightning/uiRecordApi` without specifying which fields to fetch. LDS doesn't auto-fetch all fields like an old-school SQL `SELECT *`; you must list each field you want.
Also seen asgetRecord requires fields·@wire getRecord without fields·Required parameter fields was not provided·LDS without fields
The Lightning Data Service (LDS) getRecord adapter is field-explicit by design. It fetches exactly what you list and nothing more — for performance, security, and cache efficiency.
What's required
import { LightningElement, wire } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';
import NAME_FIELD from '@salesforce/schema/Account.Name';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
export default class MyComp extends LightningElement {
@api recordId;
@wire(getRecord, { recordId: '$recordId', fields: [NAME_FIELD, INDUSTRY_FIELD] })
account;
get accountName() {
return this.account?.data?.fields?.Name?.value;
}
}
The fields property is required. Each field is imported from @salesforce/schema/<Object>.<FieldName>.
Why imports, not strings
LDS uses the @salesforce/schema/... imports to:
- Generate a static dependency — the build tool knows which fields the component reads, so deploys can warn if a field doesn't exist.
- Trigger field-rename safety — if the field gets renamed in a deploy, the import breaks at compile time.
- Enforce per-component field tracking — performance optimisations rely on knowing exactly what each component needs.
So you can't pass fields: ['Account.Name'] as a plain string. The platform rejects it.
What the wire returns
The wired property has a complex shape:
{
data: {
apiName: 'Account',
childRelationships: {},
eTag: 'xxx',
fields: {
Name: { displayValue: null, value: 'Acme Corp' },
Industry: { displayValue: 'Technology', value: 'Tech' }
},
id: '0016xxx',
lastModifiedById: '005xxx',
lastModifiedDate: '...',
recordTypeInfo: null,
systemModstamp: '...'
},
error: undefined
}
Note the indirection: data.fields.Name.value (not just data.Name). This is so picklists can carry both value (API value) and displayValue (translated label). Dotted access:
get accountName() {
return this.account?.data?.fields?.Name?.value ?? '';
}
A simpler alternative for read-only views
For just rendering a record, the lightning-record-view-form component handles all this for you:
<lightning-record-view-form record-id={recordId} object-api-name="Account">
<lightning-output-field field-name="Name"></lightning-output-field>
<lightning-output-field field-name="Industry"></lightning-output-field>
</lightning-record-view-form>
No imports, no wire, no manual field selection. The framework handles fetching, caching, and FLS.
When you need many fields
Importing 30 individual fields gets tedious. Use a LIST of strings imported via the schema namespace if you don't need static type safety:
const FIELDS = [
'Account.Name',
'Account.Industry',
'Account.AnnualRevenue',
// ...
];
This works as long as your component is module-scoped and can take a list of strings; LDS accepts both forms.
A common bug: using getRecord for write
getRecord is read-only. To update a record, use updateRecord from the same module:
import { updateRecord } from 'lightning/uiRecordApi';
await updateRecord({ fields: { Id: this.recordId, Name: 'New' } });
Don't try to mutate the wire's data and re-render — LDS won't persist that.
