MP061warning

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

migrationpilot analyze migration.sql
⚠ [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:

.migrationpilotrc.yml
rules:
  MP061: false

# or keep it, and downgrade it
rules:
  MP061:
    severity: warning

Try 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