Skip to content

PostgreSQL

Overview

PostgreSQL is the default dialect in ERDHub. It offers the richest type system of all supported dialects, making it ideal for complex schemas. ERDHub generates standard PostgreSQL DDL with:

  • CREATE TYPE ... AS ENUM for named enum types
  • SERIAL / BIGSERIAL / SMALLSERIAL for auto-increment columns
  • CREATE INDEX with btree, hash, gin, and gist index types
  • Double-quoted identifiers for reserved words and mixed-case names
  • COMMENT ON TABLE / COMMENT ON COLUMN for table and column notes

Type Mappings

The following table shows how DSL types map to PostgreSQL types when exporting SQL.

Numeric Types

DSL TypePostgreSQL TypeNotes
integer, intINTEGER4-byte signed integer
bigintBIGINT8-byte signed integer
smallintSMALLINT2-byte signed integer
serialSERIALAuto-incrementing 4-byte integer
bigserialBIGSERIALAuto-incrementing 8-byte integer
smallserialSMALLSERIALAuto-incrementing 2-byte integer
floatREAL4-byte floating point
doubleDOUBLE PRECISION8-byte floating point
decimal(p,s)DECIMAL(p,s)Exact numeric with precision and scale
numeric(p,s)NUMERIC(p,s)Same as DECIMAL
moneyMONEYCurrency amount

Boolean

DSL TypePostgreSQL TypeNotes
boolean, boolBOOLEANtrue / false

String Types

DSL TypePostgreSQL TypeNotes
textTEXTVariable-length, unlimited
varchar(n)VARCHAR(n)Variable-length with limit
char(n)CHAR(n)Fixed-length, padded

Identifier and JSON Types

DSL TypePostgreSQL TypeNotes
uuidUUID128-bit universally unique identifier
jsonJSONStored as text, validated on input
jsonbJSONBBinary JSON, supports indexing and querying

Date and Time Types

DSL TypePostgreSQL TypeNotes
dateDATECalendar date (no time)
timeTIMETime of day (no date)
timestampTIMESTAMPDate and time without timezone
timestamptzTIMESTAMPTZDate and time with timezone
timetzTIMETZTime with timezone
intervalINTERVALTime span

Binary and Network Types

DSL TypePostgreSQL TypeNotes
byteaBYTEAVariable-length binary data
inetINETIPv4 or IPv6 host address
cidrCIDRIPv4 or IPv6 network address
macaddrMACADDRMAC address

Other Types

DSL TypePostgreSQL TypeNotes
xmlXMLXML data
bitBITFixed-length bit string
varbitVARBITVariable-length bit string
tsvectorTSVECTORFull-text search document
tsqueryTSQUERYFull-text search query
hstoreHSTOREKey-value pairs (requires extension)
citextCITEXTCase-insensitive text (requires extension)

Geometric Types

DSL TypePostgreSQL TypeNotes
pointPOINT2D point
lineLINEInfinite line
lsegLSEGLine segment
boxBOXRectangular box
circleCIRCLECircle
polygonPOLYGONClosed polygon
pathPATHOpen or closed geometric path

Enum Handling

PostgreSQL uses dedicated enum types created with CREATE TYPE ... AS ENUM. ERDHub generates the CREATE TYPE statement before any table that references the enum.

sql
CREATE TYPE "post_status" AS ENUM ('draft', 'published', 'archived');
CREATE TYPE "user_role" AS ENUM ('admin', 'editor', 'viewer');

Enum types are reusable across multiple tables and columns.

Auto-Increment

PostgreSQL provides three serial types for auto-incrementing columns:

TypeRange
SMALLSERIAL1 to 32,767
SERIAL1 to 2,147,483,647
BIGSERIAL1 to 9,223,372,036,854,775,807

These are shorthand for creating a sequence and setting the column default. ERDHub uses SERIAL by default for auto-increment primary keys.

Identifier Quoting

PostgreSQL uses double quotes for identifier quoting. ERDHub quotes all identifiers to safely handle reserved words and mixed-case names:

sql
"my_table"."Column Name"

Table and Column Notes

DSL notes on tables and columns are exported as PostgreSQL COMMENT ON statements:

sql
COMMENT ON TABLE "users" IS 'Application user accounts';
COMMENT ON COLUMN "users"."email" IS 'Must be unique and verified';

Index Types

ERDHub supports four PostgreSQL index types:

Index TypeUse Case
btreeDefault. Equality and range queries on most data types
hashEquality-only lookups
ginFull-text search, JSONB, arrays, and composite values
gistGeometric data, full-text search, range types

Example Output

sql
CREATE TYPE "post_status" AS ENUM ('draft', 'published', 'archived');
CREATE TYPE "user_role" AS ENUM ('admin', 'editor', 'viewer');

CREATE TABLE "users" (
  "id" BIGSERIAL PRIMARY KEY,
  "email" VARCHAR(255) NOT NULL UNIQUE,
  "name" VARCHAR(100) NOT NULL,
  "role" "user_role" NOT NULL DEFAULT 'viewer',
  "avatar_url" TEXT,
  "is_active" BOOLEAN NOT NULL DEFAULT true,
  "metadata" JSONB,
  "created_at" TIMESTAMPTZ NOT NULL DEFAULT now(),
  "updated_at" TIMESTAMPTZ
);

CREATE TABLE "posts" (
  "id" BIGSERIAL PRIMARY KEY,
  "author_id" BIGINT NOT NULL,
  "title" VARCHAR(255) NOT NULL,
  "slug" VARCHAR(255) NOT NULL UNIQUE,
  "body" TEXT,
  "status" "post_status" NOT NULL DEFAULT 'draft',
  "view_count" INTEGER NOT NULL DEFAULT 0,
  "published_at" TIMESTAMPTZ,
  "created_at" TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE "comments" (
  "id" BIGSERIAL PRIMARY KEY,
  "post_id" BIGINT NOT NULL,
  "user_id" BIGINT NOT NULL,
  "body" TEXT NOT NULL,
  "created_at" TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX "idx_posts_author" ON "posts" USING btree ("author_id");
CREATE INDEX "idx_posts_status" ON "posts" USING btree ("status");
CREATE INDEX "idx_posts_body_search" ON "posts" USING gin (to_tsvector('english', "body"));
CREATE INDEX "idx_comments_post" ON "comments" USING btree ("post_id");

ALTER TABLE "posts" ADD CONSTRAINT "fk_posts_author"
  FOREIGN KEY ("author_id") REFERENCES "users" ("id");

ALTER TABLE "comments" ADD CONSTRAINT "fk_comments_post"
  FOREIGN KEY ("post_id") REFERENCES "posts" ("id");

ALTER TABLE "comments" ADD CONSTRAINT "fk_comments_user"
  FOREIGN KEY ("user_id") REFERENCES "users" ("id");

COMMENT ON TABLE "users" IS 'Application user accounts';
COMMENT ON COLUMN "users"."email" IS 'Must be unique and verified';
COMMENT ON TABLE "posts" IS 'Blog posts written by users';