I want to add one concrete example to sfdcfox's excellent discussion, just because I've done this before.
If you're in a situation where you need to create hundreds of fields (or even objects), you can effectively incorporate scripting into the process to cut the amount of manual work you have to do, even if other portions of the process are still manual. This applies to both Salesforce DX and regular metadata API deploys, although my example below is for the Metadata API.
One way to approach this that lowers the complexity of the scripting work you have to do is to manually create a "skeleton" object and custom field. Once you pull the source for those entities down (using a package.xml
or SFDX), you can build templates from that XML source, even as simply as using string substitution.
I once did a migration from FileMaker into Salesforce, where the primary object had >400 fields. (Yes, this was a huge design problem). I used this quick and very dirty Python script to read a field list CSV and template out Salesforce objects from it. The core mechanism works like this:
Define a dict of templates by field type:
templates["Number"] = """
<fields>
<fullName>%(fullName)s__c</fullName>
<externalId>false</externalId>
<label>%(label)s</label>
<precision>18</precision>
<required>false</required>
<scale>0</scale>
<trackTrending>false</trackTrending>
<type>Number</type>
<unique>false</unique>
</fields>
"""
templates["Text"] = """
<fields>
<fullName>%(fullName)s__c</fullName>
<externalId>false</externalId>
<label>%(label)s</label>
<length>%(length)s</length>
<required>false</required>
<trackTrending>false</trackTrending>
<type>Text</type>
<unique>false</unique>
</fields>
"""
(Note the substitution locations, which could easily be extended to cover more attributes of the fields).
Then, loop over the list of fields that you want to create, and perform string substitution against the appropriate template for the field type:
# Your code will look different depending on how you store the field list.
for key in generatedSchema:
print(templates[generatedSchema[key]["salesforceType"]] % generatedSchema[key])
That just gives you a ton of XML on standard output that you can copy and paste into your skeleton sObject XML file, and push back to Salesforce using the Metadata API.
Note that I am omitting some logic that's based on where the field list is coming from, like doing type and Text field length inference - that will depend on the application.
A similar approach could be used to generate multiple objects, fields across different objects, or to use SFDX format rather than Metadata API.
This doesn't cover the associated entities like tabs, or permission sets and profiles. It's valuable because it can take out a big chunk of work in the middle of the process, not because it handles everything (cleanly or at all). That said, you could extend the approach to generate tab metadata, and there are other tools you can use to help speed up the appropriate configuration of profiles and permission sets.