PostgreSQL JSONB for flexible schema design

Maria Garcia Feb 2026
2 tabs
-- Create table with JSONB column
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  email VARCHAR(255) NOT NULL,
  name VARCHAR(255),
  metadata JSONB DEFAULT '{}'::jsonb
);

-- Insert JSONB data
INSERT INTO users (email, name, metadata) VALUES
  ('alice@example.com', 'Alice',
   '{"age": 30, "city": "NYC", "premium": true, "preferences": {"theme": "dark"}}'::jsonb),
  ('bob@example.com', 'Bob',
   '{"age": 25, "city": "SF", "premium": false}'::jsonb);

-- Query JSONB: -> returns JSON, ->> returns text
SELECT
  name,
  metadata -> 'city' as city_json,
  metadata ->> 'city' as city_text,
  metadata -> 'preferences' ->> 'theme' as theme
FROM users;

-- Check if key exists
SELECT name
FROM users
WHERE metadata ? 'premium';

-- Check if value exists in array
SELECT name
FROM users
WHERE metadata -> 'tags' ? 'developer';

-- Contains operator (@>)
SELECT name
FROM users
WHERE metadata @> '{"premium": true}'::jsonb;

-- Containment check
SELECT name
FROM users
WHERE metadata @> '{"city": "NYC", "age": 30}'::jsonb;

-- Extract nested values
SELECT
  name,
  metadata #> '{preferences, theme}' as theme,
  metadata #>> '{preferences, notifications, email}' as email_notif
FROM users;

-- Update JSONB field
UPDATE users
SET metadata = metadata || '{"last_login": "2024-01-15"}'::jsonb
WHERE email = 'alice@example.com';

-- Set specific key
UPDATE users
SET metadata = jsonb_set(
  metadata,
  '{preferences, language}',
  '"en"'::jsonb
)
WHERE id = 1;

-- Remove key
UPDATE users
SET metadata = metadata - 'temporary_field';

-- Array operations
UPDATE users
SET metadata = jsonb_set(
  metadata,
  '{tags}',
  (COALESCE(metadata -> 'tags', '[]'::jsonb) || '"new-tag"'::jsonb)
);
2 files · sql Explain with highlit

PostgreSQL JSONB stores binary JSON efficiently with indexing support. I use JSONB for semi-structured data, dynamic attributes, event logs. JSONB operators enable querying nested data—->, ->>, @>, ?. GIN indexes accelerate JSONB queries. JSONB avoids EAV anti-pattern while maintaining flexibility. Indexing specific JSONB paths optimizes common queries. JSONB outperforms JSON—binary format, indexable. Use JSONB for polymorphic associations, metadata, user preferences. Understanding when to use JSONB versus normalized tables balances flexibility and performance. JSONB enables schema evolution without migrations. Generated columns extract JSONB fields for traditional indexing. JSONB is PostgreSQL's secret weapon for flexible data modeling.