Using JSON and JSONB in PostgreSQL: A Practical Guide with Examples

Modern applications often work with semi-structured or dynamic data, such as API responses, configuration files, or user-generated content. To support these use cases, PostgreSQL provides powerful native support for JSON and JSONB data types.

Unlike traditional relational columns, JSON data allows flexible schemas while still benefiting from PostgreSQL’s robustness, indexing, and query capabilities.

In this article, you will learn:

  • The difference between JSON and JSONB
  • When and why to use each type
  • How to insert, query, update, and index JSON/JSONB data
  • Practical examples commonly used in real-world applications

What Are JSON and JSONB in PostgreSQL?

PostgreSQL supports two JSON-related data types:

1. JSON

  • Stores data in text format
  • Preserves whitespace and key order
  • Minimal processing during insertion
  • Slower for querying

2. JSONB (Binary JSON)

  • Stores data in binary format
  • Removes whitespace and key order
  • Faster querying and indexing
  • Supports advanced operators and indexes

👉 Best practice:
Use JSONB in most cases unless you explicitly need to preserve formatting or key order.

Creating a Table with JSON and JSONB

Let’s start with a simple example.

CREATE TABLE user_profiles (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50),
    profile JSONB
);

Example JSONB data:

{
  "full_name": "John Doe",
  "email": "john@example.com",
  "skills": ["PostgreSQL", "Docker", "Linux"],
  "experience": {
    "years": 5,
    "level": "senior"
  }
}

Inserting JSONB Data

Insert JSON data using standard SQL syntax:

INSERT INTO user_profiles (username, profile)
VALUES (
    'johndoe',
    '{
       "full_name": "John Doe",
       "email": "john@example.com",
       "skills": ["PostgreSQL", "Docker", "Linux"],
       "experience": {
         "years": 5,
         "level": "senior"
       }
     }'
);

PostgreSQL automatically validates JSON syntax before storing the data.

Querying JSON and JSONB Data

Accessing Top-Level Keys

Use the -> and ->> operators:

SELECT
    profile->'full_name' AS name_json,
    profile->>'full_name' AS name_text
FROM user_profiles;
  • -> returns JSON
  • ->> returns text

Accessing Nested JSON Fields

SELECT
    profile->'experience'->>'level' AS experience_level
FROM user_profiles;

Filtering with JSONB Data

Find users with senior-level experience:

SELECT username
FROM user_profiles
WHERE profile->'experience'->>'level' = 'senior';

Working with JSON Arrays

Query Elements Inside an Array

SELECT username
FROM user_profiles
WHERE profile->'skills' ? 'PostgreSQL';

The ? operator checks if a key or array element exists.

Expand JSON Arrays into Rows

SELECT
    username,
    jsonb_array_elements_text(profile->'skills') AS skill
FROM user_profiles;

Useful for reporting and analytics queries.

Updating JSONB Data

Update a Single Key

Use jsonb_set to modify part of a JSONB document:

UPDATE user_profiles
SET profile = jsonb_set(profile, '{email}', '"newemail@example.com"')
WHERE username = 'johndoe';

Add a New Key

UPDATE user_profiles
SET profile = jsonb_set(
    profile,
    '{last_login}',
    '"2025-01-10"',
    true
)
WHERE username = 'johndoe';

The true flag allows adding a new key if it does not exist.

Removing Keys from JSONB

Remove a key using the - operator:

UPDATE user_profiles
SET profile = profile - 'last_login'
WHERE username = 'johndoe';

JSONB Indexing for Performance

One of the biggest advantages of JSONB is indexing support.

GIN Index for JSONB

CREATE INDEX idx_user_profiles_profile
ON user_profiles
USING GIN (profile);

This dramatically improves performance for:

  • Key existence checks
  • Containment queries
  • Complex JSON filters

Containment Queries

Find users with a specific skill:

SELECT username
FROM user_profiles
WHERE profile @> '{"skills": ["PostgreSQL"]}';

The @> operator checks if the JSON document contains a specific structure.

JSON vs JSONB: When to Use Which?

FeatureJSONJSONB
Storage formatTextBinary
Query performanceSlowerFaster
Index supportLimitedFull
Preserves formattingYesNo
RecommendedRarelyMost use cases

Recommendation:
Use JSONB for application data, APIs, and analytics.

Common Use Cases for JSONB in PostgreSQL

  • Storing API responses
  • User preferences and settings
  • Event logs and metadata
  • Semi-structured data in microservices
  • Hybrid relational + NoSQL design

Best Practices

  • Avoid storing everything in JSONB — relational columns are still faster for fixed attributes
  • Create indexes only when necessary
  • Keep JSON documents reasonably small
  • Validate JSON structure at the application level when possible

Conclusion

PostgreSQL’s JSON and JSONB features provide an excellent balance between flexibility and performance. With powerful operators, indexing capabilities, and native validation, JSONB enables PostgreSQL to handle modern application data without sacrificing reliability.

By understanding how to query, update, and index JSONB effectively, you can design databases that are both scalable and maintainable.

You may also like