DEV Community

Nicholas Petrasek
Nicholas Petrasek

Posted on AI-assisted

Your import preview is a proposed change, not just a parsed CSV

An import screen can parse a file successfully, show a convincing table, and still leave the user unsure what clicking Import will do.

Consider a preview that says:

80 records will be created
20 records will be updated
3 rows need attention
Enter fullscreen mode Exit fullscreen mode

That is useful only if the user can understand the matching rule, inspect the changes, and trust that the commit will follow the same contract.

This is a design approach I would use for an admin import flow. The example is hypothetical; it is not a claim about a particular product's implementation.

Parse into a plan

Parsing tells you what the file contains. Planning tells you what those values mean for the application.

A plan might contain:

{
  "sourceRow": 12,
  "action": "update",
  "recordId": "customer-42",
  "expectedVersion": 7,
  "changes": {
    "displayName": {
      "before": "Acme Ltd",
      "after": "Acme Limited"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This shape is illustrative, not an API specification. Its purpose is to make the decision visible: which row matched which record, what would change, and which record version the plan used.

I would also show rejected and ambiguous rows. A file row that matches multiple records should not disappear into a generic error count.

Decide what can become stale

Between preview and commit, another user may edit a record or create a new one that matches an imported identifier.

There are several reasonable policies:

  • Reject stale plans and ask for a fresh preview.
  • Revalidate at commit and show conflicts for review.
  • Apply unaffected rows while reporting conflicting rows separately.

The choice depends on the product. What I would avoid is silently changing the matching rule or overwriting newer values while continuing to imply that the original preview was applied.

The server needs to enforce the chosen rule. If a version check happens before the write without an atomic guard, another change can still occur between them.

Define what a retry means

Suppose the server imports the rows, but the response never reaches the browser. The user clicks again.

Is that a retry of the same approved operation, or a new import?

An operation identifier can help the server recognize retries, but it needs a real contract: where the identifier is stored, how long it remains valid, and whether a different payload with the same identifier is rejected.

The button label alone cannot solve duplicate writes.

Make partial results actionable

If partial application is allowed, I want the result to explain:

  1. Which rows were applied.
  2. Which were skipped or rejected, and why.
  3. Whether retrying the remaining rows can repeat successful writes.
  4. Where to inspect the resulting records.

Keep row numbers tied to the original file. Users should not have to reconstruct which line an error refers to after sorting the preview.

An undo feature can be valuable, but reversing an import may conflict with edits made afterward. “Undo” needs its own policy for intervening changes; it is not automatically equivalent to restoring a database snapshot.

The review I would run

Before calling the flow ready, I would test a duplicate identifier, an ambiguous match, a record changed after preview, a lost success response, and a retry of a partially applied import.

Those cases connect backend correctness with the UI's promise. A clean preview table is only one part of that promise.

If you build admin tools, which import behavior do users ask for first: better matching, a clearer diff, useful errors, or safer retries?

Top comments (0)