How to fix Too many columns in PostgreSQL
PostgreSQL enforces a hard limit of 1,600 columns per table. This error occurs when you exceed that limit or hit the 1,664-column tuple limit in SELECT statements. Redesign your schema using arrays, JSON, or table partitioning.
Quick fix
Fixes Too many columns
SELECT COUNT(*) as column_count
FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'your_table_name';- Check your current column count
- Redesign your schema with normalization
- Use JSON or JSONB for semi-structured data
- Use arrays for repeated columns
SELECT COUNT(*) as column_countFROM information_schema.columnsWHERE table_schema = 'public' AND table_name = 'your_table_name';Too many columns
What this error means
PostgreSQL has hard-coded limits on the number of columns it can handle. The primary limit is 1,600 columns per table (MaxHeapAttributeNumber), and a secondary limit of 1,664 for tuple target lists in SELECT statements (MaxTupleAttributeNumber). These limits exist because the tuple structure has fixed-size field offsets in its header, making it impossible to exceed without recompiling PostgreSQL. Additionally, dropped columns continue to count toward the limit—PostgreSQL never reclaims space from dropped columns.
Typical symptoms
- CREATE TABLE fails with "ERROR: tables can have at most 1600 columns"
- SELECT queries fail with "ERROR: target lists can have at most 1664 entries"
- Joining or selecting from multiple wide views fails mid-query
- Adding a new column fails after dropping columns (limit still counts drops)
Common causes
- Designing tables with more than 1,600 columns (rare but happens with flattened data or poorly normalized schemas)
- Joining multiple wide tables or views creates an intermediate result set exceeding 1,664 columns
- Repeatedly adding and dropping columns eventually hits the limit because dropped columns still count
- Using SELECT * on nested views where upstream views have hundreds of columns
How to fix "Too many columns"
Run this query to see how many columns your table has:
SELECT COUNT(*) as column_count
FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'your_table_name';If the result is near or over 1,600, you've hit the limit.
Break wide tables into multiple normalized tables with foreign keys:
-- Before (too wide)
CREATE TABLE users (
id INT,
name TEXT,
prop_1 TEXT, prop_2 TEXT, ... -- 1,500+ properties
);
-- After (normalized)
CREATE TABLE users (id INT PRIMARY KEY, name TEXT);
CREATE TABLE user_properties (
id INT PRIMARY KEY,
user_id INT REFERENCES users(id),
key TEXT,
value TEXT
);This pattern scales to unlimited properties.
If you have many dynamic or optional fields, store them in a single JSONB column:
CREATE TABLE products (
id INT PRIMARY KEY,
name TEXT,
metadata JSONB -- stores hundreds of optional attributes
);
INSERT INTO products VALUES (1, 'Widget', '{"color": "red", "weight": 2.5, "tags": ["sale", "new"]}'::jsonb);
SELECT metadata->'color' FROM products WHERE id = 1;JSONB supports indexing and querying while keeping your table structure clean.
For columnar repetition (like multiple phone numbers or addresses), use arrays:
CREATE TABLE contacts (
id INT PRIMARY KEY,
name TEXT,
phone_numbers TEXT[], -- can store 100+ numbers in one column
addresses TEXT[]
);
INSERT INTO contacts VALUES (1, 'Alice', ARRAY['555-1234', '555-5678'], ARRAY['123 Main St']);
SELECT phone_numbers[1] FROM contacts WHERE id = 1;If joining views causes the error, explicitly select only needed columns instead of SELECT *:
-- Instead of this:
SELECT * FROM view_a
JOIN view_b ON view_a.id = view_b.id; -- ERROR: too many columns
-- Do this:
SELECT view_a.id, view_a.name, view_b.description
FROM view_a
JOIN view_b ON view_a.id = view_b.id;This reduces the tuple size and stays within limits.
If you've reached 1,600 columns and many are marked as dropped, you must rebuild the table:
-- Dump schema and data
pg_dump -t your_table_name your_db > table.sql
-- Create new table (ideally redesigned)
DROP TABLE your_table_name CASCADE;
-- Restore from dump or insert redesigned data
psql -d your_db < table.sqlNote: This is a last resort after redesigning your schema. PostgreSQL does not provide a way to reclaim the dropped-column slots without recreation.
Advanced notes
The 1,600 and 1,664 limits are hard-coded in PostgreSQL source (src/include/access/htup_details.h) and cannot be changed without recompiling. These limits exist because tuple headers use fixed-size offsets for field positions. Additionally, the actual per-row storage size is further constrained by PostgreSQL's 8KB heap page size—even if you stay under 1,600 columns, if your row data exceeds ~8KB, it cannot be stored. Dropped columns permanently consume a slot in the tuple structure and count toward the 1,600 limit, so aggressive column dropping over time can unexpectedly hit the limit. For OLAP or data warehouse scenarios with hundreds of semi-structured attributes, using JSONB or Parquet external tables is recommended. For OLTP with many optional nullable columns, normalization or EAV (Entity-Attribute-Value) patterns are more appropriate.
Frequently asked questions
- What does "Too many columns" mean?
- PostgreSQL has hard-coded limits on the number of columns it can handle. The primary limit is 1,600 columns per table (MaxHeapAttributeNumber), and a secondary limit of 1,664 for tuple target lists in SELECT statements (MaxTupleAttributeNumber). These limits exist because the tuple structure has fixed-size field offsets in its header, making it impossible to exceed without recompiling PostgreSQL.
- How do I fix "Too many columns"?
- PostgreSQL enforces a hard limit of 1,600 columns per table. This error occurs when you exceed that limit or hit the 1,664-column tuple limit in SELECT statements. Redesign your schema using arrays, JSON, or table partitioning.
- What causes "Too many columns"?
- Designing tables with more than 1,600 columns (rare but happens with flattened data or poorly normalized schemas) Joining multiple wide tables or views creates an intermediate result set exceeding 1,664 columns Repeatedly adding and dropping columns eventually hits the limit because dropped columns still count
- Is the "Too many columns" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.