Create Table

Learn how to use the PostgreSQL CREATE TABLE statement to define new tables with columns, data types, and constraints.

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

Quick Answer

Use CREATE TABLE table_name (column1 datatype constraint, ...) to define a new table. Specify column names, data types, and constraints such as PRIMARY KEY, NOT NULL, UNIQUE, CHECK, and FOREIGN KEY. Use IF NOT EXISTS to avoid errors when the table already exists.

Spin up a Postgres database in 20 seconds with Vela.

Try Vela Sandbox

The CREATE TABLE statement is how you define the structure of a new table in PostgreSQL. Every column requires a name and a data type, and you can attach constraints to columns or to the whole table to enforce data integrity rules. Getting your table definition right at the start saves you from costly migrations later.

CREATE TABLE syntax

The basic syntax is:

CREATE TABLE [IF NOT EXISTS] table_name (
  column1 datatype [(length)] column_constraint,
  column2 datatype [(length)] column_constraint,
  ...
  table_constraints
);

Key points:

  • The table name must be unique within its schema. PostgreSQL defaults to the public schema.
  • IF NOT EXISTS causes PostgreSQL to issue a notice rather than an error if the table already exists.
  • Column constraints include NOT NULL, UNIQUE, PRIMARY KEY, CHECK, DEFAULT, and REFERENCES (foreign key).
  • Table-level constraints (defined after the columns) can reference multiple columns, such as composite primary keys or multi-column unique constraints.

CREATE TABLE example

The following statement creates an accounts table with several constraints:

CREATE TABLE accounts (
  user_id    SERIAL PRIMARY KEY,
  username   VARCHAR(50)  UNIQUE NOT NULL,
  password   VARCHAR(50)  NOT NULL,
  email      VARCHAR(255) UNIQUE NOT NULL,
  created_at TIMESTAMP    NOT NULL,
  last_login TIMESTAMP
);

After running the statement you should see:

CREATE TABLE

Inspect the resulting structure in psql with d accounts:

Table "public.accounts"
   Column   |            Type             | Nullable |                  Default
------------+-----------------------------+----------+-------------------------------------------
 user_id    | integer                     | not null | nextval('accounts_user_id_seq'::regclass)
 username   | character varying(50)       | not null |
 password   | character varying(50)       | not null |
 email      | character varying(255)      | not null |
 created_at | timestamp without time zone | not null |
 last_login | timestamp without time zone |          |
Indexes:
    "accounts_pkey" PRIMARY KEY, btree (user_id)
    "accounts_email_key" UNIQUE CONSTRAINT, btree (email)
    "accounts_username_key" UNIQUE CONSTRAINT, btree (username)

Notice that SERIAL automatically creates a sequence and sets it as the column default. The UNIQUE constraints also implicitly create indexes.

CREATE TABLE best practices

  • Always specify NOT NULL on columns that should never be empty — it is cheaper to enforce this at the database level than in application code.
  • Use BIGSERIAL or BIGINT GENERATED ALWAYS AS IDENTITY for primary keys in high-volume tables to avoid exhausting the INTEGER range.
  • Declare FOREIGN KEY constraints to maintain referential integrity between related tables.
  • Use TIMESTAMPTZ instead of TIMESTAMP for columns recording real-world event times to avoid time-zone ambiguity.
  • Use IF NOT EXISTS in deployment scripts so they remain idempotent and safe to re-run.

Reference: PostgreSQL documentation — CREATE TABLE.

Continue in Managing Tables: Select Into.

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

Frequently Asked Questions

How do I create a table only if it does not already exist?

Add IF NOT EXISTS between CREATE TABLE and the table name: CREATE TABLE IF NOT EXISTS table_name (...). PostgreSQL will issue a notice and skip creation if the table already exists, rather than returning an error.

What is the difference between a column constraint and a table constraint?

A column constraint is declared inline with a single column definition and applies only to that column. A table constraint is declared after all column definitions and can reference multiple columns, making it necessary for composite primary keys, multi-column unique constraints, and multi-column check constraints.

How do I create a table in a specific schema?

Prefix the table name with the schema name: CREATE TABLE myschema.mytable (...). If you omit the schema, PostgreSQL places the table in the first schema on the search_path, which defaults to public.

Does CREATE TABLE automatically create indexes?

Yes, PostgreSQL automatically creates a B-tree index for each PRIMARY KEY and UNIQUE constraint. Other constraint types such as CHECK, NOT NULL, and FOREIGN KEY do not automatically create indexes — you must create them manually with CREATE INDEX.

What happens if I try to create a table with a name that already exists?

PostgreSQL returns an error: ERROR: relation "table_name" already exists. To avoid this in scripts, use CREATE TABLE IF NOT EXISTS, which issues a NOTICE instead of an error and leaves the existing table unchanged.