CONCEPT Cited by 1 source
Column-order conflict¶
Definition¶
A column-order conflict is a schema-merge conflict class where two concurrent deploy branches each add a distinct column to the same table, both without specifying position — so the final column ordering differs depending on the merge order. Even though both orderings produce schemas that are functionally equivalent in terms of stored data, they differ in physical column position and are therefore treated as conflicting under the diff commutativity check.
Canonical verbatim framing (Noach, 2023 PlanetScale):
"The order of columns in a table matters. Queries that run a
SELECT * FROM customerand use positional arguments will get different columns at positions3and4. The two branches conflict with each other. This is similar to a Git merge conflict where two branches append different rows to the end of a file." (Source: sources/2026-04-21-planetscale-database-branching-three-way-merge-for-schema-changes)
The mechanism¶
Baseline main:
Two branches independently add columns:
-- branch1: adds subscription_type
ALTER TABLE customer
ADD COLUMN subscription_type enum('free', 'promotional', 'paid');
-- branch2: adds joined_at
ALTER TABLE customer
ADD COLUMN joined_at timestamp NOT NULL DEFAULT current_timestamp();
Composed in either order, both compositions succeed (MySQL is happy to apply each diff). But the resulting column orderings differ:
-- diff1(diff2(main)):
customer(id, name, joined_at, subscription_type)
-- diff2(diff1(main)):
customer(id, name, subscription_type, joined_at)
The commutativity check compares the final schemas for equality — these two differ — so the merge is flagged as a conflict.
Why column order matters in MySQL¶
Column order affects:
SELECT *output order. Clients that index the result set by position (row[2],row[3]) break when the positions change.INSERTwithout column list.INSERT INTO customer VALUES (…)is positional; adding a column shifts the meaning of the tuple.- Binary log format
ROWreplication. Row images are ordered by column position, so replication consumers may need coordination. SHOW CREATE TABLEand migration tooling round-trip. Tools that compare schemas textually will see different output.
Even though none of these affect stored data values, all affect consumers observing the table.
Resolution: anchor the column¶
The conflict is resolved by one branch explicitly
anchoring the new column with AFTER <existing-column>:
-- branch1, revised to anchor position:
ALTER TABLE customer
ADD COLUMN subscription_type enum(…)
AFTER id;
With this, branch1's new column is pinned to position 2,
and branch2's joined_at (unanchored) will go last
regardless of merge order. The two orderings now produce
identical schemas, and the commutativity check passes.
From the post:
"We could avoid the conflict if one of the branches positioned the new column anywhere but last."
Analogy to Git¶
Git exhibits the same pattern when two branches both append lines to the end of a file. Unlike source code, MySQL can reorder columns mechanically — so in principle the conflict is resolvable by a merge policy ("new columns go at the end, branch1 first"). PlanetScale chooses instead to flag it and let the developer decide, treating physical ordering as a meaningful schema property.
Contrast with indexes (deliberate asymmetry)¶
The post explicitly exempts index ordering from the
commutativity check: "PlanetScale disregards index
ordering." The reasoning is that index order is
observable only through SHOW CREATE TABLE and
INFORMATION_SCHEMA introspection — not through query
semantics. Column order, by contrast, affects SELECT *
positional semantics used by real application code.
This asymmetry reflects a pragmatic judgement: flag the conflict class that clients can observe through data-path queries; exempt the class that only changes metadata-path output.
Limitations¶
- Physical-position-only. Column-order conflict is purely structural. It does not extend to semantic-order conflicts (e.g., two branches reshaping the primary key differently).
- Platform-dependent. Column order is less significant in some databases (particularly NoSQL or column-store engines where physical column order is an optimisation detail, not a schema invariant).
- Policy, not mathematics. A different system could legitimately treat column-order differences as non-conflicts by adopting a "new columns go last" canonicalisation. PlanetScale's choice is conservative rather than mathematically forced.
Seen in¶
- sources/2026-04-21-planetscale-database-branching-three-way-merge-for-schema-changes
— canonical worked example. Two branches add different
columns to
customerwithout position anchors;diff1(diff2(main)) != diff2(diff1(main))on column order. Resolution is to anchor one column withAFTER id.