The quick answer
Load one Project with record type job. Use getFields for body field IDs and getField for available labels and types. Enumerate getSublists and getSublistFields separately. Write the results to CSV while preserving metadata failures. Describe the export as one loaded record context, rather than a complete account-wide field catalog.
This walkthrough runs a SuiteScript 2.1 helper against a local N/record mock and writes a real local CSV. The returned field set and one injected metadata failure are fixture data. No account Project is loaded, no field values are exported and no record is saved. The local model tests the export contract; it does not verify account permissions or native field coverage.
Before you start
The fixture represents Harbor Service Project, internal ID 79001, with SuiteScript record type job. Oracle documents job as the Project record type. In an account, the Projects feature and access to the selected record are prerequisites. Oracle: Project record
The helper is a module example for an appropriate SuiteScript execution context. It is not a deployed script or a command to paste into an arbitrary browser console. Use authorized execution, account-specific access and a known record ID when adapting it.
Keep these sources separate:
- Custom Entity Fields describes custom field definitions and applicability.
- A loaded N/record instance exposes runtime field IDs and metadata in its execution context.
- The Records Browser documents standard scriptable record IDs and fields.
- Page XML, saved-search results and other API schemas have their own scope and support rules.
01. Separate custom definitions from runtime metadata
In the local Custom Entity Fields list, Site Reference has script ID custentity_site_reference and Project applicability Y. Internal Note also applies to Project. Customer Segment applies only to Customer in this fixture.
The list's ID column contains a field script ID. It is not the numeric internal ID of the field-definition record, and the list does not enumerate standard Project fields.
These three definitions are fictional local data. The recording reuses the native-style definition list; it does not create fields in an account.
02. Use job for the Project record type
The deliberate first command asks the local harness to export type project, ID 79001. The mock rejects that unsupported type and produces no CSV from that command. The displayed LOCAL_UNSUPPORTED_TYPE message is local test behavior, not a captured platform error code.
Use job, or record.Type.JOB, when loading a Project through N/record. The corrected module uses standard mode:
const rec = record.load({
type: record.Type.JOB,
id: projectId,
isDynamic: false
});
Changing the type does not establish role access, feature availability or the existence of a particular record. Verify those separately in the target account.
03. Export body metadata and sublist IDs separately
Run the helper with job and 79001. For each ID from getFields, it calls getField and reads label and type when available. A per-field catch retains the ID and error when metadata retrieval fails. The example does not sort or assume that the returned order matches a customized form. Oracle: getFields, Oracle: getField
Then it calls getSublists and getSublistFields. Those rows are marked scope=sublist, include the sublist ID and intentionally leave label/type blank. It does not read any sublist line or recurse into subrecords. Oracle: getSublists, Oracle: getSublistFields
The local writer creates project_field_dictionary.csv. A CSV parser verifies seven data rows and eight columns: five body rows, two sublist rows and one retained metadata error. The file contains 418 UTF-8 bytes. The helper loads the fixture once and makes zero getValue or save calls.
Those two sublist rows describe field IDs, not two resource records. The helper calls neither getLineCount nor getSublistValue.
The local filesystem writer is outside NetSuite. The recording does not implement N/file persistence, a Suitelet response, a deployment or a bulk account discovery process.
04. Inspect the parsed CSV
The viewer is built from the actual CSV parser's output. It shows six columns and summarizes the two repeated identity columns, recordType and recordId, above the table. The downloaded file contains all eight columns on every row.
Body rows include entityid → Project ID, companyname → Project Name, startdate → Start Date and custentity_site_reference → Site Reference. The custentity_internal_note row remains present with blank label/type and MOCK_METADATA_UNAVAILABLE. That failure was deliberately injected in the mock; it does not establish how a real restricted field behaves.
The two jobresources rows contain jobresource and role. Their blank labels and types are intentional: this export collects sublist IDs only. Standard IDs are checked against Oracle's Project reference; the particular returned set remains a mock fixture. Oracle: Project Records Browser
Customer-only custentity_customer_segment is absent from this mocked Project set even though its definition exists in the local list. This illustrates the difference between definition inventory and runtime context; it is not a live permission test.
05. Verify the download and its scope
Download project_field_dictionary.csv. The capture driver compares its bytes exactly with the actual local export and records the same SHA-256. Every parsed row retains recordType=job and recordId=79001.
The five-body-plus-two-sublist count belongs to this fixture. A loaded-record dictionary does not enumerate every possible field across account features, forms, customizations and roles. Presence in this export also does not prove support in saved searches, SuiteQL, REST, SOAP, workflows or CSV import. Verify the schema for the tool you intend to use.
Common questions
Does getFields include sublist fields?
It returns body field IDs, including machine and matrix header fields. Use getSublists and getSublistFields for separate sublist enumeration. This example does not read sublist values or subrecords.
Does this produce every field that could exist on a Project?
It describes one loaded record context. Compare standard definitions with the Records Browser and account custom definitions with their configuration lists. Neither comparison makes a single runtime export an account-wide catalog.
Why are label and type blank on some rows?
Sublist rows are intentionally ID-only. A body row can lack metadata or retain an error. These are different cases; inspect scope and error rather than treating every blank as a failure.
Does MOCK_METADATA_UNAVAILABLE prove a role-permission restriction?
It is an injected local exception that tests whether the helper retains a field ID and continues. It does not reproduce a particular NetSuite access error or prove permissions in an account.
Can I export labels and types in standard mode?
The record.Field label and type properties are available in standard and dynamic modes. Some other properties, such as isDisplay, require dynamic mode; they are outside this example. Oracle: record.Field
Can an ordinary saved-search export replace this dictionary?
A search result exports its selected data columns. This helper enumerates runtime field metadata instead. A saved search's configured column names can help document that search, but do not establish every field on the underlying record type.
Are custom definitions merged into the runtime export?
The helper includes a custom field only when its ID is returned by the loaded record mock. The separate definition list is a comparison source; it is not merged into the CSV.
Does the script export record values or save anything?
The helper reads metadata and makes no getValue or save calls. The harness writes a CSV to the local filesystem. Loading an account record and saving a file in NetSuite would require separately authorized execution and implementation.