Created Date Wrong After Import: Every Record Says Today
After an import or migration, every record shows today's created date because the created date is a fact about the receiving system, not about the customer, and most systems will not let you override it. Salesforce and Microsoft Dataverse allow it, both only on the initial insert and both as a one-way door; HubSpot contacts, Airtable, and Notion do not allow it at all. The durable fix is to carry a business date you own, such as customer since or original created date, into every system as its own field and to key every age-based automation and report on that field instead of the system audit field.
You migrated 4,000 customers into the new CRM on Tuesday, and on Wednesday every one of them was created on Tuesday. The 2019 accounts, the ones from last month, all of them, stamped within the same eleven minutes. That is not an import bug. The created date is a fact about the receiving system, not about the customer, and most systems will not let you overwrite it. Salesforce and Microsoft Dataverse allow it, both only on the initial insert and both as a one-way door. HubSpot contacts, Airtable, and Notion do not allow it at all. The fix that survives every one of these is to carry a business date you own into each system as its own field, and to stop keying age-based automations and reports on the system's audit field.
Three dates that get called "created"
The word "created" is doing three jobs, and a migration collapses them into one.
The first is the business event: the day this person became a customer, the day the deal opened, the day the work order was raised. That date belongs to you and does not change when you switch tools.
The second is the source-system created date: when your old CRM first saw the record. Usually close to the business event, sometimes not. A customer who called in 2018 and was typed into the old system during a 2021 cleanup has a business date and a source created date three years apart.
The third is the receiving-system created date: when the new system first saw the record. After a migration, that is the import. Every platform we cover here treats this third date as an audit field it owns, sets it on insert, and, with two exceptions, refuses to let you touch it.
The bug is not that the third date is wrong. It is correct. The record did arrive on Tuesday. The bug is that every workflow, filter, and report in the new system was built to read the third date as if it were the first.
What each system lets you do with created date on import
We checked every row against the vendor's current documentation in September 2026.
| System | Can you set created date on import? | How | The catch | Last modified date |
|---|---|---|---|---|
| Salesforce | Yes, on insert only | Enable "Create Audit Fields" under Setup, User Interface; grant "Set Audit Fields upon Record Creation"; map your column to CreatedDate in Data Loader or the API | Salesforce's knowledge article states it "only works for INSERT, not UPSERT," that Modify All Data is required, and that existing records must be exported, deleted, and re-imported as new records | Settable on insert through the same feature, with documented exceptions for Tasks linked to other records |
| Microsoft Dataverse (Dynamics 365) | Yes, on import | Map your source column to overriddencreatedon, not createdon, with the prvOverrideCreatedOnCreatedBy privilege | Microsoft's documentation describes a swap: createdon receives your value and overriddencreatedon receives the actual import time. The privilege name implies you can override createdby too; the docs say that "is not currently supported" | Not importable. The docs say you "cannot import data into the modifiedon, createdby, and modifiedby columns" and recommend custom columns |
| HubSpot contacts and companies | No | None. Create date "is automatically set by HubSpot" | The accepted community answer is a custom date property such as Original Create Date | Automatically set. HubSpot's own example: log a call from yesterday today, and Last modified date shows today |
| HubSpot deals | Yes | Deal Create date "is set automatically by HubSpot, but can be manually edited by users," so it can be corrected after the fact | Deals are the only HubSpot object where this holds; the contacts and companies attached to them keep the import date | Automatically set |
| Airtable | No | The createdTime field type is read-only in the field model; it records when the record was created in this base | A date field you add and populate is the only carrier | lastModifiedTime is also read-only |
| Notion | No | The API reference states "the created_time value can't be updated" | Same: a date property you own | "The last_edited_time value can't be updated" |
Two things in that table decide the plan. First, only two systems give you a real override, and both restrict it to the moment of insert. Get the date right on the first write or accept the custom-field route. Second, nobody lets you set last modified. After a migration, the last modified date on every record is the import, and every "stale record" filter, "modified since" polling trigger, and "last touched by a human" report in the new system is now reading the migration as a human touch. That is not fixable at the audit field. It is only fixable by moving that logic to a field you own.
The two one-way doors
Salesforce and Dataverse both allow the override, and both have a trap built into the affordance.
In Salesforce, the feature is insert-only, and "insert" is stricter than it sounds. Salesforce's knowledge article on Create Audit Fields says the feature "does not permit values to be updated, only inserted (this only works for INSERT, not UPSERT)." An upsert is the natural migration verb: it matches on an external ID and creates or updates as needed. Run your migration as an upsert with CreatedDate mapped and the dates land on nothing. Run it as an insert and it works, once. If you find out on Wednesday that you forgot to enable the feature on Tuesday, Salesforce's own remedy is to export the records, delete them, and insert them again. That issues new record IDs, which breaks every lookup that pointed at the old ones, every activity attached to them, and any external-ID mapping you already handed to another system. We wrote about how far a bad ID propagates in CSV imports that mangle IDs, and this is the same blast radius in reverse.
A second Salesforce wrinkle catches teams migrating email history: the same article notes that when Enhanced Email is on and EmailMessage records are inserted, the Task records auto-created for them get the insertion date, not the EmailMessage's CreatedDate. Your emails carry the right dates. The activity timeline built from them does not.
In Dataverse the door is a different shape. You map your source date to overriddencreatedon, and during import Dataverse writes your value into createdon and writes the import timestamp into overriddencreatedon. It is a swap, and it is the correct design: the system keeps its own audit truth in a field with an honest name and gives the business-facing field to you. The trap is the mapping. Map to createdon directly and nothing happens. Map to overriddencreatedon without the prvOverrideCreatedOnCreatedBy privilege and nothing happens. Both failures are silent; the import succeeds and every record says today.
The test for both systems is the same and it takes ten minutes. Insert one record with a created date of five years ago. Open it. If the date reads five years ago, run the batch. If it reads today, stop, because the batch will read today too and one of the two systems will not let you fix it without re-keying every record.
What breaks when "created" means "arrived here"
This is the part the migration guides skip. They tell you how to set the field, or that you cannot, and stop. The damage is downstream, in everything that computes age.
Onboarding and nurture sequences enroll on created date. "Contact created in the last 7 days" now matches 4,000 records, and 3,800 of them have been customers for years. The welcome email goes to a client who has paid you 60 invoices. This is the migration-day cousin of the problem we covered in backfilling automations on existing records: there, the risk is every watcher on the table firing once at import time. Here, the risk persists, because the field that says "new" keeps saying it for a week, a month, or whatever window the filter uses.
Cohort and retention reporting keys on created date. Every native "new customers by month" chart in the new system shows one enormous bar in the migration month and nothing before it. Revenue-per-customer-age, time-to-first-purchase, and lifetime value by cohort all collapse into a single cohort called Tuesday. Nobody notices until a quarterly review, and then nobody trusts the dashboard again.
Service-level and stale-record logic keys on both dates. A "no activity in 90 days" cleanup workflow sees last modified equal to the import and leaves every migrated record alone for 90 days, then flags all of them on the same afternoon. An SLA timer that measures from record creation gives every migrated open ticket the same start time.
Deduplication and record-merge rules often prefer the older record as the survivor. With every migrated record carrying the same created timestamp, "oldest wins" is a coin flip, and the survivor is whichever row the import wrote first. We covered why merge rules need a real key in matching customer records without a shared ID, and created date is one of the tiebreakers that a migration quietly poisons.
Every one of these is the same defect: something computed age from a field that means "arrived in this system," and after a migration that field carries no information about the customer.
Own the business date
The rule we apply on every migration and every ongoing sync, regardless of what the target allows, is this: every system carries a date field you own, populated from the source, and every age-based automation and report reads that field.
Name it for what it is. customer_since, original_created_at, or first_seen_at are all fine. What matters is that the name tells the next person it is not the system audit field. Carry two companions with it: source_system and source_record_id, so the record can always be traced back to where the date came from.
Populate it at the moment of migration from the source's created date, or from the business event date if you have one and it is better. Then make it write-once. A two-way sync must never update it, and a re-import must never overwrite it, because the day a sync treats it as an ordinary field is the day it drifts. The overwrite patterns in two-way syncs apply here in full; this is exactly the kind of field that needs to be excluded from the conflict resolver.
Where the target allows the override, do that too. Salesforce's native reports, HubSpot's deal dashboards, and Dataverse's built-in views all read the system field, and populating it correctly on insert makes those work without rebuilding them. But do not let the override replace the custom field. The override is a one-time privilege on one system. The custom field survives the next migration, the next tool added to the chain, and the day this data gets pushed into something that has no override at all.
Then re-point the logic. Open every workflow enrollment filter, list, segment, and report that references created date or last modified date, and ask which of the three dates it actually needs. Onboarding wants the business date. "New this week" dashboards want the business date. A "records the integration touched today" debugging view wants the system date, and that is roughly the only thing that does. In our experience the audit field is almost never the right choice, and most filters were only using it because it was there.
One last detail that is easy to lose on the way in: the date itself has to survive the import format. A created date column that arrives as 03/04/2021 will be read as March 4 by one system and April 3 by another, and a date without a time zone shifts by a day at the boundary. We covered the mechanics in dates that land one day off; on a migration, run that check on the created-date column before anything else, because a business date that is wrong by a day is worse than a system date that is honestly the import.
What to do next
If the migration has already happened, pull one report from the new system: count of records by created date. If one day holds most of the total, every age-based automation in that system is running on the migration date. List the workflows and reports that reference created date or last modified date, add the business date field, populate it from the old system's export, and move the filters over one at a time, starting with anything that sends a message to a customer.
If the migration has not happened yet, do the ten-minute single-record test on the target first, and add the business date field before the first batch runs, not after. The field costs five minutes. The cleanup without it runs into weeks, and it is one of the first things we check when rebuilding reporting on top of a migrated data set. If you are in the middle of one and want a second pair of eyes on the field mapping before the batch goes in, tell us which two systems are involved at /contact.
Frequently Asked Questions
SOURCES & CITATIONS
- Considerations and Activation of Create Audit Fields in Salesforce (Knowledge Article 000386065) — Salesforcehttps://help.salesforce.com/s/articleView?id=000386065&type=1
- Run data import (Microsoft Dataverse): Import auditing data — Microsoft Learnhttps://learn.microsoft.com/en-us/power-apps/developer/data-platform/run-data-import
- HubSpot's default contact properties — HubSpothttps://knowledge.hubspot.com/properties/hubspots-default-contact-properties
- Web API: field model (created time and last modified time) — Airtablehttps://airtable.com/developers/web/api/field-model
About Alexey Yushkin
Alexey is the founder of GENERAL INFORMATICS LLC. He designs and ships AI and automation systems for businesses and operators across the US.
Related reading
Want this kind of system in your business?
We build practical AI and automation systems for operators. Send us your current workflow and we will show you what to automate first.
