Copy Table

Learn how to copy a PostgreSQL table with or without data using CREATE TABLE AS TABLE, including how to handle indexes and constraints that are not copied automatically.

4 min read · Last updated: March 2026 · Back to overview

Quick Answer

Use CREATE TABLE new_table AS TABLE existing_table; to copy both the structure and all data of a table. Add WITH NO DATA to copy only the structure. Note that indexes and constraints are not copied — you must add them manually with ALTER TABLE.

Spin up a Postgres database in 20 seconds with Vela.

Try Vela Sandbox

PostgreSQL provides several CREATE TABLE ... AS forms for copying a table. All of them copy the column definitions and data you specify, but none of them copy indexes, primary keys, foreign keys, or other constraints. Those must be added manually after the copy.

Three ways to copy a table

Copy structure and all data:

CREATE TABLE new_table AS TABLE existing_table;

Copy structure only, with no rows:

CREATE TABLE new_table AS TABLE existing_table WITH NO DATA;

Copy structure and a filtered subset of rows:

CREATE TABLE new_table AS
SELECT * FROM existing_table
WHERE condition;

Step-by-step example

Create the source table and insert rows:

CREATE TABLE contacts (
  id         SERIAL PRIMARY KEY,
  first_name VARCHAR NOT NULL,
  last_name  VARCHAR NOT NULL,
  email      VARCHAR NOT NULL UNIQUE
);

INSERT INTO contacts (first_name, last_name, email)
VALUES
  ('John',  'Doe',     '[email protected]'),
  ('David', 'William', '[email protected]')
RETURNING *;

-- Output:
--  id | first_name | last_name | email
-- ----+------------+-----------+---------------------------
--   1 | John       | Doe       | [email protected]
--   2 | David      | William   | [email protected]

Copy the table including its data:

CREATE TABLE contact_backup AS TABLE contacts;

Verify the copied data:

SELECT * FROM contact_backup;

-- Output:
--  id | first_name | last_name | email
-- ----+------------+-----------+---------------------------
--   1 | John       | Doe       | [email protected]
--   2 | David      | William   | [email protected]

Inspect the copy — notice that indexes are not present:

d contact_backup

-- Table "public.contact_backup"
--    Column   | Type    | Nullable
-- ------------+---------+---------
--  id         | integer |
--  first_name | varchar |
--  last_name  | varchar |
--  email      | varchar |
-- (No indexes listed)

Restore the primary key and unique constraint manually:

ALTER TABLE contact_backup ADD PRIMARY KEY (id);
ALTER TABLE contact_backup ADD UNIQUE (email);

Production tips

  • Use CREATE TABLE ... AS TABLE ... WITH NO DATA to create an empty clone for testing schema changes without duplicating large data sets.
  • After copying, always run d table_name to confirm which indexes and constraints are missing and need to be added.
  • For large tables, consider creating indexes with CREATE INDEX CONCURRENTLY after the copy to avoid long locks.
  • If you need an exact structural clone including all constraints and indexes, use pg_dump -t source_table | psql target_db instead.
  • Copying with a WHERE clause is useful for creating audit or archive tables that hold only a time-bounded subset of rows.

Continue in Managing Tables: Back to tutorial overview.

Related in this section: PostgreSQL Data Types · Create Table · Select Into

Frequently Asked Questions

Does CREATE TABLE AS TABLE copy indexes and constraints?

No. CREATE TABLE AS TABLE copies column definitions and data, but not primary keys, foreign keys, unique constraints, check constraints, or indexes. You must add those manually with ALTER TABLE after the copy.

How do I copy a table structure without copying any data?

Append WITH NO DATA: CREATE TABLE new_table AS TABLE existing_table WITH NO DATA; This creates an empty table with the same column definitions but no rows.

Can I copy only some rows when copying a table?

Yes. Use the SELECT form: CREATE TABLE new_table AS SELECT * FROM existing_table WHERE condition; Only rows matching the WHERE clause are copied to the new table.

What is the difference between CREATE TABLE AS TABLE and SELECT INTO?

Both create a new table from a query result. CREATE TABLE AS TABLE is the SQL-standard form and is generally preferred. SELECT INTO is a PostgreSQL extension that works similarly but is not portable to other databases.

How do I make a full backup copy of a table including all constraints and indexes?

Use pg_dump to dump just the source table and restore it under a new name. The CREATE TABLE AS approach copies data but not constraints or indexes, so pg_dump is the safer choice for a complete structural clone.