Field filtering
Generate only the fields your application uses, with strict validation and safe relationship metadata.
Field filtering is useful when a Salesforce object is so large that generating every field makes the schema noisy or expensive to work with.
It is optional. Without a field rule, codegen keeps every field visible through Describe.
Include or exclude exact fields
import { defineConfig } from "@kysoql/codegen";
export default defineConfig({
objects: ["Account", "Contact", "User"],
fields: {
Account: {
include: ["Id", "Name", "Industry", "OwnerId"],
},
Contact: {
exclude: ["Description"],
},
},
output: "src/kysoql/salesforce.generated.ts",
});Account keeps only the listed fields. Contact keeps every described field except Description. User has no rule, so it keeps its full described field set.
Field names are exact, case-sensitive Salesforce API names. Wildcards, relationship paths, regular expressions, and callbacks are not supported.
Include every field the query needs
An include list needs more than the fields you return to the caller. Keep fields used by:
WHEREORDER BYGROUP BYand aggregates- semi-joins
- required object-specific predicates
- lookup relationships
- child relationship metadata
No field is silently added back, including Id.
Validation rules
| Configuration | Result |
|---|---|
| No rule for an object | Keep every described field. |
include: ["Id", "Name"] | Keep exactly those fields. |
exclude: ["Description"] | Keep every field except Description. |
exclude: [] | Keep every field but still mark the object as explicitly filtered. |
Both include and exclude | Reject the rule. |
Empty include or a rule that removes every field | Reject the rule. |
| Unknown field name | Reject generation before replacing the output file. |
| Duplicate names | Deduplicate them deterministically. |
A field can be unknown because it was renamed, removed, hidden from the authenticated user, or simply misspelled.
Field rules do not add objects
The objects list still decides which objects are generated. A field rule for Contact does not add Contact when the selected object list contains only Account.
pnpm exec kysoql generate --object AccountThat command keeps the configured Account field rule and ignores inactive rules for generation.
To generate a full object without loading configured field rules, use --no-config:
pnpm exec kysoql generate --no-config \
--auth config/salesforce.auth.ts \
--object Account \
--output src/account-full.generated.tsRelationship fields matter
For Contact.Account.Name, you need:
Contactin the generated object listContact.AccountIdretainedAccountin the generated object listAccount.Nameretained
For a child relationship such as Account.Contacts, retain the lookup field on the child object. There is no Contacts field to place in the parent object's include list because child relationships come from relationship metadata.
Removing a lookup removes the parent path derived from it and can also remove the inverse child relationship.
Polymorphic reference metadata keeps its original target union. Filtering out one possible target object does not rewrite Salesforce metadata to pretend the reference has only one target.
See polymorphic relationships for TYPEOF and .Type behaviour.
Why FIELDS() is disabled on filtered objects
An object with an explicit field rule is marked as a partial generated schema. Typed selectFields("standard"), selectFields("custom"), and selectFields("all") are disabled for that object.
Salesforce expands FIELDS(...) on the server. A local TypeScript field filter cannot change what Salesforce considers part of FIELDS(ALL).
Use explicit selections instead:
import { db } from "./db";
const query = db.selectFrom("Account").select(["Id", "Name"]);Even exclude: [] marks the object as partial because a rule was explicitly applied. Remove the rule and regenerate when you want to restore typed FIELDS() support.
Programmatic generation
The same ObjectFieldFilters type works with generateSchema() and loadSchema():
import {
generateSchema,
type ObjectFieldFilters,
type SalesforceDescribeClient,
} from "@kysoql/codegen";
const fields = {
Account: { include: ["Id", "Name", "OwnerId"] },
Contact: { exclude: ["Description"] },
} satisfies ObjectFieldFilters;
export async function generate(client: SalesforceDescribeClient) {
await generateSchema({
client,
objects: ["Account", "Contact"],
fields,
output: "src/kysoql/salesforce.generated.ts",
});
}What field filtering does not do
Field filtering narrows generated metadata and the TypeScript query surface. It does not:
- enforce Salesforce field-level security
- change the fields Salesforce returns unless your SOQL selection changes
- reduce the metadata requests made during generation
- validate runtime Salesforce response fields
Treat it as a developer-experience and schema-size tool, not a security feature. See security and production use for the actual trust boundaries.