#3796·atlas

`-- atlas:renamed_from` is silently ignored when the desired state comes from `data "external_schema"` — renames plan as DROP COLUMN + ADD COLUMN

Author: jcndadCreated Sep 14, 2026Updated Sep 14, 2026

Atlas version: v1.3.0 (reproduced on Linux CI via ariga/setup-atlas and on Windows locally) Driver: PostgreSQL 17

Summary

The -- atlas:renamed_from <prev> SQL directive (Declarative Schema Renames) produces ALTER TABLE … RENAME COLUMN when the SQL desired state is passed as file://. When the same SQL bytes reach Atlas through data "external_schema", the directive is ignored and atlas migrate diff plans DROP COLUMN + ADD COLUMNat exit 0, with no warning. The generated migration would destroy the column's data.

Reproduction

Prior state (the migration directory's baseline), pre.sql:

sql
CREATE SCHEMA IF NOT EXISTS crm;
CREATE TABLE "crm"."probe_col" ("id" uuid PRIMARY KEY, "tenant_id" uuid NOT NULL, "ai_confidence" numeric);
CREATE INDEX "idx_probe_col_conf" ON "crm"."probe_col" ("ai_confidence");

Desired state, f.sql:

sql
CREATE SCHEMA IF NOT EXISTS crm;
CREATE TABLE IF NOT EXISTS crm.probe_col (
  id                                       uuid NOT NULL,
  tenant_id                                uuid NOT NULL,
  -- atlas:renamed_from ai_confidence
  confidence_ai                            numeric,
  CONSTRAINT probe_col_pkey PRIMARY KEY (id)
);
CREATE INDEX IF NOT EXISTS idx_probe_col_conf ON crm.probe_col (confidence_ai);

atlas.hcl:

hcl
data "external_schema" "p" {
  program = ["cat", "f.sql"]
}
env "ext" {
  src = data.external_schema.p.url
  dev = "postgres://…/dev?sslmode=disable"   # an empty database
  migration { dir = "file://migrations" }
}

Each case uses a fresh migration directory seeded with the same baseline:

atlas migrate diff baseline --dir file://migrations --to file://pre.sql --dev-url <dev>
atlas migrate diff rename_probe --env ext                                     # A
atlas migrate diff rename_probe --env ext --to file://f.sql                   # B
atlas migrate diff rename_probe --dir file://migrations --to file://f.sql --dev-url <dev>   # C

Observed

case desired state via plan
A data "external_schema" DROP INDEX …; ALTER TABLE "crm"."probe_col" DROP COLUMN "ai_confidence", ADD COLUMN "confidence_ai" numeric NULL; CREATE INDEX … — exit 0, no warning
B same env, --to file://f.sql ALTER TABLE "crm"."probe_col" RENAME COLUMN "ai_confidence" TO "confidence_ai";
C file://f.sql ALTER TABLE "crm"."probe_col" RENAME COLUMN "ai_confidence" TO "confidence_ai";

Controls: with the directive removed, both the data "external_schema" input (A) and the file:// input (C, also used by B) plan DROP + ADD. So the directive is what differs, and on identical bytes only the external_schema input discards it.

atlas migrate lint does flag a column drop (DS103) in the same environment, so the gap is in planning, not analysis. The silence is what makes it dangerous: migrate diff exits 0 with a destructive plan and gives no indication that a directive in the input was not applied.

Expected

Either the directive is honoured for SQL loaded through data "external_schema", or Atlas reports that directives are not supported on that input rather than silently producing a destructive plan. The rename documentation covers HCL and SQL schemas and does not say external schemas are excluded.

Workaround

Write the program's output to a file and pass --to file://<file> (case B).