A data import is not finished when it works once on a clean database. It is finished when the team understands what happens after a partial failure, a corrected source file or a second run of the same job.
Design the import around repeatability. The operator should be able to inspect the plan, identify the records affected and recover without guessing which rows were already written.
Choose a stable identity
Decide how a source record maps to a destination record. A row number is rarely a durable identity because sorting the file changes it. A display name can also change or be shared by several records.
Use a source identifier where one exists and define the scope in which it is unique. If several suppliers provide data, the supplier identity may need to be part of the key. Record that mapping explicitly so later updates find the intended record.
For a hypothetical property import, a cottage's title might change while its booking-system identifier stays the same. Matching by title could create a duplicate instead of updating the existing page.
Preview the intended changes
Before writing, calculate which records would be created, updated, skipped or rejected. Show counts and representative differences. Make a destructive operation, such as removing absent records, a deliberate mode rather than an invisible consequence of an incomplete file.
Validate required fields and relationships before the main write stage where practical. A reference to a missing category may be something the import can create, a reason to skip one record or a reason to stop. Choose the behaviour and explain it to the operator.
Keep the original input identifiable. A file name alone may not distinguish two corrected versions. Store a checksum or another suitable version reference with the run record.
Record progress at a useful boundary
Choose whether the import should succeed atomically or commit in controlled batches. A small configuration import may suit one transaction. A long-running catalogue job may need checkpoints and explicit partial completion.
Whichever approach you choose, make the state durable. A process restart should not erase the only record of what happened. Keep per-record outcomes where they are needed to explain failures or resume safely.
For updates, define which fields the source owns. An import should not overwrite an editor's carefully written description merely because the source file contains an empty value. Distinguish a missing field, an explicit request to clear it and a supplied replacement.
Prove the second run
Run the same input twice in a test environment. The second run should have a predictable outcome: usually no unnecessary duplicates or changes. Then modify one source record and confirm that only the intended destination fields change.
Test an interrupted run, a missing relationship and a file with duplicate identifiers. Check that the report explains the problem in terms the operator can act on, rather than only showing a stack trace.
A good import leaves an audit trail and a recovery path as well as new data. Our integration engineering treats those as part of the feature, particularly when the process will be repeated by someone who did not write the original script.