-
1
Decide whether a custom object is actually the right answer
The first question is not how to build the object. It is whether the object should exist. Custom objects carry a permanent cost: every field becomes a migration risk, every relationship becomes a report dependency, every layout becomes something admins must maintain. Before you create anything, ask three questions. Does an existing object already model this entity, even imperfectly? Could a custom field or a related list on an existing object solve the problem? Will this entity be queried, reported, and permissioned independently from its parent? If the answer to the first two is yes and the third is no, you do not need a custom object. You need a field. Common cases where custom objects are genuinely the right answer: assets or equipment tied to accounts, policies or contracts with their own lifecycle, projects or engagements that outlast a single deal, licenses or subscriptions tracked at a granularity below the account, and physical locations or sites when accounts can have many. Everything else deserves a hard second look before you add schema. The cheapest custom object is the one you do not build.
- Write a one-paragraph description of the entity and what makes it distinct from existing objects
- List every attribute you expect to track and ask whether each could live on an existing object
- Confirm the entity has its own lifecycle, its own permissions, or its own reporting needs
- Get written sign-off from the data owner before you create the object in a sandbox
Tip: If you cannot write a one-sentence definition of what a record of this object represents, the object is not ready to be built. Go back and sharpen the definition first.
-
2
Design the schema on paper before you touch the CRM
Open a document, not the CRM. Draft the object as if you were specifying a database table because, under the hood, that is what you are doing. List every field you intend to carry. For each field, write the field type, whether it is required, whether it has a default value, and what downstream report or automation consumes it. Then do the brutal work of cutting. The first draft of any custom object schema is always too long. Admins add fields because someone on a Zoom call said they would like to see one, and six quarters later the record page is a wasteland of empty columns nobody fills. A healthy custom object launches with ten to twenty fields. More than thirty is a code smell. If the list keeps growing, you are probably trying to model two separate entities as one. Split them, relate them, and ship both leaner than the monolith would have been. The paper draft also forces you to name fields consistently. Pick a convention early. If related dates are called "signed_date" on one object and "signature_timestamp" on another, your downstream analysts will spend their careers writing CASE statements to reconcile the two.
- Write the full field list in a document with type, required flag, default, and downstream consumer per field
- Cut every field that does not feed a report, a required business decision, or a system of record
- Agree on a naming convention for dates, amounts, identifiers, and status fields before you create the first field
- If the field list exceeds thirty, challenge whether this is really one object or two
Tip: A field without a named downstream consumer is a field that will be empty, inconsistent, or wrong within two quarters. If nobody reads it, do not create it.
-
3
Pick the right field type for every attribute
Field type is where custom objects most often go sideways. Text fields are tempting because they accept anything, which is exactly the problem. Any attribute with a finite set of values must be a picklist, not free text. Any attribute that represents money must be a currency field with a defined precision. Any attribute that represents a date must be a date or datetime field, never a text field, because text dates make every downstream report a parsing nightmare. Boolean fields are for binary states only; if there is any chance of a third value in the future, use a picklist with two values today so you can extend it tomorrow without a migration. Rich text is for genuine prose content and should be rare on custom objects. Numbers need thought: integer versus decimal, signed versus unsigned, with a precision that reflects actual business usage. A quantity of licenses is an integer. A conversion rate is a decimal with three or four places. Formula and rollup fields are powerful but should be reserved for calculations that genuinely do not belong in a report; every formula field is a performance tax on every record query. Multi-select picklists are the most abused field type in CRM history: they look flexible, they report terribly, and they almost always should be a related object or a set of booleans instead.
- Convert every finite-answer field to a picklist with locked values and a defined display order
- Use currency fields for all monetary attributes with an explicit precision and ISO currency code
- Use date or datetime fields for every temporal attribute; never store dates as text
- Reserve multi-select picklists only when the values are truly orthogonal and reporting on them does not matter
Tip: If an admin wants to add a text field "just in case," ask what report it feeds. The silence is the answer.
-
4
Model the relationships before you create the first record
A custom object in isolation is a spreadsheet. Its value comes from how it connects to the rest of your schema. Decide early which existing object this one hangs off and what cardinality the relationship carries. Most custom objects relate to accounts, which is a many-to-one: an account has many assets, many policies, many sites. Some custom objects relate to contacts: a certification belongs to a person, not a company. A few sit between two objects as a junction, like an account-contact role record that captures a person's role on a specific account. Pick the cardinality explicitly. One-to-many is the default and the simplest. Many-to-many requires a junction object, which is its own schema with its own permissions. Avoid implicit many-to-many via multi-select fields; it looks easier at setup and breaks at reporting. Decide also whether the parent relationship is a lookup or a master-detail. A master-detail cascades deletes and shares permissions, which is powerful and dangerous. Use master-detail when the child object has no life without the parent, like line items under a quote. Use lookup when the child can exist independently, like a contact linked to an account but survivable if the account is merged. Document every relationship in the schema diagram you drafted in step two. Future admins will thank you.
- For every relationship, write down parent object, child object, cardinality, and lookup versus master-detail
- Avoid implicit many-to-many relationships expressed as multi-select picklists; use junction objects
- Use master-detail only when the child has no business meaning without the parent
- Diagram all relationships in a single schema document that lives alongside your admin runbook
Tip: If you cannot explain the cardinality in one sentence ("one account has many sites, each site has exactly one account"), the relationship is probably wrong.
-
5
Build the record layout for the people who will actually use it
The record layout is where schema meets human attention. It is also where most custom objects quietly fail: admins build a layout that mirrors the field list in creation order, and the result is a wall of inputs that reps avoid. Lay out the record page in sections keyed to how the record is actually read. Put identity fields at the top: name, parent record, status, owner. Put the fields a user needs to make a decision in the second section: dates, amounts, next steps, flags. Put reference fields and metadata in a third section near the bottom: created date, source, legacy identifiers. Put rarely-touched or audit fields in a collapsible section so they do not scroll fatigue the user. Then do the same work for mobile. Most CRM admins forget that reps increasingly open records on phones between meetings; a layout that looks fine on a 1440 pixel laptop is punishing on a 390 pixel iPhone. Confirm the mobile layout actually works by opening the record on your own phone before you ship. Related lists are part of the layout decision too. Show the related objects that matter for day-to-day work; hide the ones that only matter for audits. A related list that is always empty for a given object type signals a cardinality decision that should be revisited.
- Group fields into Identity, Decision, Reference, and Audit sections; collapse Audit by default
- Place the three to five fields that drive the next business action above the fold
- Test the layout on a phone before shipping; adjust sections and column counts until it is readable
- Show related lists that drive daily workflows and hide the ones that only matter for auditors
Tip: Open the record on your own phone. If you cannot find the field a rep updates most often within three seconds, the layout is wrong.
-
6
Scope permissions, record ownership, and sharing
Permissions are the step admins skip and later regret. Decide, before launch, who can create records of this object, who can read all records, who can read only their own or their team's records, who can edit, and who can delete. The default on most CRMs is far too permissive; it inherits from the generic admin profile and gives everyone the keys. Walk the permission matrix role by role: executive admin, revenue ops, sales manager, sales rep, customer success, support, read-only analyst. For each, pick create, read, update, delete, or none, and write it down. Then decide ownership. Every record needs an owner, and the owner drives default sharing in most CRMs. If this object is owned by a rep, the owner should be the rep who created or claimed the record. If it is owned centrally, by revenue ops or finance, set a service account as the default owner and build an automation to assign ownership on creation. Finally, decide sharing. Private records visible only to the owner and their management chain, team-shared records visible to a defined group, or org-wide read with per-field edit restrictions. The right answer depends on the object, but the wrong answer is "we will figure it out later." Later means never, and the data becomes a privacy incident waiting to happen.
- Draw a permission matrix: rows for roles, columns for create/read/update/delete; fill every cell
- Set an explicit default record owner; use a service account only when ownership is central
- Choose a sharing model (private, team, or org-wide) and document the reason behind the choice
- Confirm field-level security separately: some fields should be visible to admins but not reps
Tip: If you cannot name the person responsible for approving changes to the permission matrix on this object, the matrix will drift. Appoint an owner first.
-
7
Wire automations, validation rules, and triggers
A custom object without automation is a static table. Automation is what makes it participate in the business. Start conservative. Add validation rules that enforce the required-field logic you specified in step two: amount must be positive, close date cannot be in the past at creation, status cannot move backward without a reason code. Validation rules are blocking rules; keep them to the ones that genuinely must be true, because every blocked save is a user support ticket waiting to happen. Then add required automations: assign owner on creation, stamp a created-by-source field, notify the owner on status change, create a related task when a specific status is reached. Resist the urge to automate everything on day one. Every automation is a thread of logic that must be maintained, debugged, and reasoned about. Admins who build fifteen automations at launch spend the next year explaining why records are in surprising states. Build the three or four automations that are genuinely required, ship them, watch them, and add more only when a specific business pain demands it. Keep triggers readable: name them for what they do, document the trigger condition inline, and avoid chained triggers that fire on the records they themselves modify. Chained triggers are the single most common source of CRM infinite loops and silent data corruption.
- Add validation rules only for conditions that must be true at save; everything else is a workflow concern
- Build the three or four automations that are genuinely required at launch; defer the rest
- Name every automation for what it does and document the trigger condition in a comment
- Avoid chained triggers that modify the records that fired them; they are an infinite-loop risk
Tip: A validation rule that fires more than once per rep per week is a design problem, not a discipline problem. Rewrite the rule or redesign the field.
-
8
Migrate real data, then open the object to users
The last step is the one most teams fumble: moving real records into the object and opening the floodgates. Do not import production data on day one. Build the object in a sandbox or dev environment, load twenty representative records by hand, and walk through every workflow: create, read, update, delete, report, permission check, mobile layout, automation firing. Have two or three real users sit at a shared screen and try to break it. They will. Fix what they find. Then run a dry-run import of production data against the dev environment, confirm field mappings, confirm picklist values match (surprise picklist mismatches are the number one cause of bulk-import pain), and confirm that every automation fires on the migrated records exactly as expected. Only after that dry run passes do you touch production. Freeze changes to the source data during the production import. Import in batches small enough to roll back if something goes wrong, log the import ID on every record for traceability, and spot-check the first batch before continuing. Open the object to users in waves: admins first, then one pilot team, then the rest of the business. Announce the launch, document the schema in your admin runbook, and schedule a thirty-day review to see which fields are actually being used and which should be retired. Custom objects are living systems. The schema you launch is draft one, not the final answer.
- Load twenty representative records by hand in a sandbox and walk every workflow end to end
- Have two or three real users try to break the object before any production import
- Dry-run the production import against the sandbox and reconcile every picklist mismatch
- Import to production in batches, log import IDs on records, and open the object to users in waves
Tip: Schedule the thirty-day review before launch, with the date on calendars. If it is not on the calendar, it will not happen.