Renaming a column in PostgreSQL is done with the ALTER TABLE ... RENAME COLUMN statement. Unlike many schema changes, this operation is safe for dependent objects: PostgreSQL automatically cascades the rename to views, foreign key constraints, triggers, and stored procedures that reference the column.
Syntax
ALTER TABLE table_name
RENAME COLUMN old_column_name TO new_column_name;
The COLUMN keyword is optional:
ALTER TABLE table_name
RENAME old_column_name TO new_column_name;
To rename multiple columns, run a separate statement for each — there is no single-statement shortcut:
ALTER TABLE products RENAME COLUMN sku TO product_code;
ALTER TABLE products RENAME COLUMN list_price TO unit_price;
If the column does not exist, PostgreSQL raises an error. There is no IF EXISTS guard for RENAME COLUMN.
Practical Example
Create sample tables with a view that references a column you will rename:
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
label VARCHAR NOT NULL
);
CREATE TABLE products (
id SERIAL PRIMARY KEY,
title VARCHAR NOT NULL,
sku VARCHAR NOT NULL UNIQUE,
list_price NUMERIC(10, 2),
category_id INT,
FOREIGN KEY (category_id) REFERENCES categories (id)
);
CREATE VIEW product_catalog AS
SELECT
p.id,
p.title,
p.sku,
c.label AS category_label
FROM products p
INNER JOIN categories c ON c.id = p.category_id;
Rename sku to product_code:
ALTER TABLE products RENAME COLUMN sku TO product_code;
Rename label in categories, which the view references:
ALTER TABLE categories RENAME COLUMN label TO category_name;
PostgreSQL automatically updates the view definition. Inspect it to confirm:
\d+ product_catalog
-- View definition:
-- SELECT p.id, p.title, p.product_code, c.category_name AS category_label
-- FROM products p
-- JOIN categories c ON c.id = p.category_id;
Check the foreign key constraint is still intact:
SELECT
conname AS constraint_name,
contype,
pg_get_constraintdef(oid) AS definition
FROM pg_constraint
WHERE conrelid = 'products'::regclass;
How CASCADE Affects Rename
RENAME COLUMN propagates automatically to:
| Object type | Behavior |
|---|---|
| Views | Column reference updated in view definition |
| Foreign keys | Constraint updated to reference the new name |
| Triggers | Column references in trigger functions updated |
| Stored procedures | References in function bodies updated |
| Indexes | Index definition updated automatically |
Testing Column Renames with Vela
Column renames in production carry risk — application code, ORM models, and query strings may still reference the old name. Vela’s database branching lets you test the rename on a production-like branch before touching the live database: create a branch from production (an instant copy-on-write clone), run the RENAME COLUMN migration, point your CI environment at the branch connection string, then run your full test suite — ORM queries, API tests, and raw SQL — before merging to production. This eliminates the “rename in prod and hope” pattern that causes incidents.
Auditing Dependents Before Renaming
Use pg_depend to find all views that reference a column before you rename it:
SELECT
dependent_ns.nspname AS schema,
dependent_view.relname AS view_name
FROM pg_depend
JOIN pg_rewrite
ON pg_depend.objid = pg_rewrite.oid
JOIN pg_class AS dependent_view
ON pg_rewrite.ev_class = dependent_view.oid
JOIN pg_class AS source_table
ON pg_depend.refobjid = source_table.oid
JOIN pg_attribute
ON pg_depend.refobjid = pg_attribute.attrelid
AND pg_depend.refobjsubid = pg_attribute.attnum
JOIN pg_namespace AS dependent_ns
ON dependent_ns.oid = dependent_view.relnamespace
WHERE source_table.relname = 'products'
AND pg_attribute.attname = 'sku';
Run this before every rename to know exactly what will be affected.
Production Tips
- Column renames are metadata-only — they do not rewrite table data and are very fast even on large tables.
- PostgreSQL acquires an
ACCESS EXCLUSIVElock during the rename, blocking reads and writes briefly. Run renames during low-traffic windows for busy tables, or use a maintenance window. - Update application code, ORM models, and raw query strings before or immediately after the rename to avoid runtime errors.
- In migration frameworks (Flyway, Liquibase, Rails), pair the rename with a corresponding rollback that renames the column back.
- If zero-downtime is required, consider a multi-step approach: add the new column, write to both, backfill, migrate reads, then drop the old column.