PostgreSQL in Practice

PostgreSQL Types, JSONB, and Extensions

PostgreSQL’s rich type and extension systems can encode domain meaning and unlock specialized operators, but every choice also fixes comparison, indexing, portability, privilege, upgrade, and recovery behavior.
  • Choose the narrowest semantic type, not the shortest syntax.
  • JSONB is queryable binary structure, not a schema exemption.
  • Operator classes connect operators to indexes.
  • Arrays suit atomic bounded collections.
  • Enums and domains have distinct change boundaries.
  • Extensions are executable dependencies.
Native-type decision table
TypeGood fitIndex/operator consequenceWatch
uuidopaque distributed identityB-tree equality/order; hash equalityrandom locality and textual ingestion
numericexact money/measurementsB-tree; exact arithmeticprecision and CPU versus integer minor units
timestamptzinstantsB-tree and range predicatesrender in explicit zone; not civil schedule
range/multirangeinterval setsGiST/SP-GiST overlap/containmentbounds and exclusion semantics
inet/cidrnetwork addresses/prefixesB-tree plus GiST/SP-GiST operator classesaddress versus network intent
arraybounded atomic collectionGIN containment/overlapupdates rewrite row; limited integrity
jsonbsparse/evolving document fragmentGIN or expression indexes by operatorweak relational constraints and broad indexes
enum/domainstable labels / reusable scalar constraintunderlying comparison semanticsmigration and cast behavior
Extend the canonical commerce products safely
-- Existing commerce.products(product_id, sku, name, current_price) remains authoritative.
CREATE DOMAIN commerce.positive_money AS numeric(19,4) CHECK (VALUE >= 0);
ALTER TABLE commerce.products
  ADD COLUMN attributes jsonb NOT NULL DEFAULT '{}'::jsonb,
  ADD COLUMN available_during tstzmultirange;
CREATE TABLE commerce.product_price_quotes (
  quote_id uuid PRIMARY KEY,
  product_id bigint NOT NULL REFERENCES commerce.products(product_id),
  quoted_price commerce.positive_money NOT NULL,
  valid_during tstzrange NOT NULL
);
CREATE INDEX products_attributes_gin
  ON commerce.products USING gin (attributes jsonb_path_ops);
SELECT product_id, sku, current_price
FROM commerce.products
WHERE attributes @> '{"color":"blue"}'::jsonb;
Inventory extension provenance before installation
SELECT name, version, installed, superuser, trusted, relocatable, schema, requires
FROM pg_available_extension_versions ORDER BY name, version;
-- Install only a pinned, reviewed package available on every server image.
CREATE EXTENSION IF NOT EXISTS pg_stat_statements WITH SCHEMA public;
SELECT extname, extversion, extowner::regrole FROM pg_extension;