suboptimal-column-order
CREATE TABLE has variable-length columns before fixed-size columns, wasting alignment padding.
- operation
- Columns
- lock taken
- no table lock
- remediation
- Manual rewrite
- category
- Types & schema style
What triggers it
A CreateStmt with 3 or more columns where at least one variable-length type (anything not in the rule's hardcoded fixed-size set — text, varchar, jsonb, bytea, etc.) is declared before a fixed-size type (int, bigint, timestamp, uuid, and others) that appears later in the column list.
What does not
Tables with fewer than 3 columns, tables where every fixed-size column already precedes the variable-length ones, and tables that are all one kind (all fixed or all variable) — firstFixedAfterVar never gets set and the check returns null.
Where it applies
Applies to every PostgreSQL version MigrationPilot targets. It works on the SQL text alone — no database connection needed.
The lock, and what it blocks
No lock applies — this is a CREATE TABLE, so there's no existing table being altered. The concern is on-disk storage layout on the new table, not locking.
Why it matters
PostgreSQL stores columns in declaration order. Fixed-size types (int, bigint, timestamp, uuid) before variable-length types (text, jsonb, bytea) reduces alignment padding waste — saving 4-16 bytes per row on tables with mixed types.
Unsafe, and safe
Flagged
CREATE TABLE users ( name TEXT, bio TEXT, id INTEGER, age INTEGER );
Safe alternative
CREATE TABLE users ( id INTEGER, age INTEGER, name TEXT, bio TEXT );
What it assumes
The rule only recognizes its own hardcoded list of fixed-size type names, so a custom domain or an enum wrapping a fixed-size value would be treated as variable-length and could produce a false positive. It also assumes the padding waste matters, which only holds once the table accumulates enough rows for a few bytes each to add up.
What the CLI prints
⚠ [MP061] WARNING (line 1) Table "users": place fixed-size columns (id, age) before variable-length columns (name, bio) to reduce alignment padding. Why: PostgreSQL stores columns in declaration order. Fixed-size types (int, bigint, timestamp, uuid) before variable-length types (text, jsonb, bytea) reduces alignment padding waste, saving 4-16 bytes per row on tables with mixed types. Docs: https://migrationpilot.dev/rules/mp061
Generated by running the CLI's own formatter over the flagged example above, so it is the text the tool actually produces. A real run also reports the other rules that fire on the same statement; those blocks are left out here.
Turning it off
For one statement, put a comment on the line before it:
-- migrationpilot-disable MP061 CREATE TABLE users (
For the whole project, in .migrationpilotrc.yml — by name or by id:
rules:
MP061: false
# or keep it, and downgrade it
rules:
MP061:
severity: warningTry it
Open this rule's flagged example in the playground. It runs in your browser — edit it and watch the finding appear and disappear.
Run MP061 in the playground