Skip to main content
PostgreSQL
CHAPTER 23 Intermediate

JSON and JSONB in PostgreSQL

Updated: May 16, 2026
6 min read

# CHAPTER 23

JSON and JSONB in PostgreSQL

1. Introduction

Historically, developers had to choose: Do I use a Relational Database (SQL) for strict data integrity, or a Document Database (NoSQL, like MongoDB) for flexible, unstructured data? PostgreSQL destroyed this dilemma. It possesses native, world-class support for storing, querying, and indexing JSON documents directly alongside standard relational columns. In this chapter, we will learn how to turn PostgreSQL into a hybrid powerhouse using the legendary JSONB data type.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the difference between JSON and JSONB data types.
  • Insert JSON payloads into a table.
  • Extract specific keys and values from deeply nested JSON objects.
  • Query tables by filtering against internal JSON values.
  • Understand how to index JSONB for lightning-fast lookups.

3. JSON vs JSONB

PostgreSQL offers two distinct data types:
  • JSON: Stores the exact string of text you send it. It is fast to insert, but incredibly slow to query because Postgres has to re-parse the text every time you read it.
  • JSONB (JSON Binary): When you insert data, Postgres parses the JSON, strips out whitespace, and converts it into a highly optimized binary format on the hard drive. It is slightly slower to insert, but lightning fast to query and index.

*The Golden Rule: Always use JSONB in production applications. Never use standard JSON.*

4. Creating a JSONB Table

Let's build a users table. The core data is strictly relational, but we want a flexible preferences column to store random frontend settings (dark mode, notification toggles, etc.) without having to alter the table structure every time a new setting is invented.
sql
12345
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(100) UNIQUE,
    preferences JSONB -- The Magic Column!
);

5. Inserting JSONB Data

You insert JSON data exactly as you would insert a normal string, ensuring it is properly formatted JSON.
sql
12345
INSERT INTO users (email, preferences) 
VALUES (
    'john@example.com', 
    '{"theme": "dark", "notifications": {"email": true, "sms": false}, "role": "admin"}'
);

6. Querying JSONB (The Extraction Operators)

To look *inside* the JSON payload, PostgreSQL uses special arrow operators.
  • -> Returns the data as a JSON object.
  • ->> Returns the data extracted as raw Text (This is the one you will use 99% of the time).
sql
12345678
-- Extract the 'theme' value for all users
SELECT email, preferences->>'theme' AS ui_theme 
FROM users;
-- Output: john@example.com | dark

-- Traverse deeply nested JSON! (Get the SMS notification preference)
SELECT email, preferences->'notifications'->>'sms' AS wants_sms 
FROM users;

7. Filtering via JSONB inside the WHERE Clause

You can use the extraction operator directly inside a WHERE clause to treat the JSON keys exactly like standard SQL columns!
sql
1234567
-- Find ALL users who have dark mode enabled
SELECT email FROM users 
WHERE preferences->>'theme' = 'dark';

-- Find ALL users who are administrators
SELECT email FROM users 
WHERE preferences->>'role' = 'admin';

8. Mini Project: The E-Commerce Payload

E-Commerce orders are highly complex. An order might have variable metadata (gift wrapping, delivery instructions, coupon codes). Instead of creating 20 empty relational columns, we store it in a metadata JSONB column.
sql
123456789101112131415
CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    total NUMERIC,
    metadata JSONB
);

-- Insert a complex order
INSERT INTO orders (total, metadata) VALUES (
    150.00, 
    '{"gift_wrap": true, "message": "Happy Birthday!", "tags": ["urgent", "vip"]}'
);

-- Query: Find all orders tagged as 'urgent' using the JSONB Contains Operator (@>)
SELECT order_id FROM orders 
WHERE metadata @> '{"tags": ["urgent"]}';

9. Common Mistakes

  • Overusing JSONB: If you have data that is structured and relational (like firstname or dateofbirth), DO NOT put it in a JSONB column! JSONB is for unstructured, variable data. Relational columns are significantly smaller, faster, and benefit from strict NOT NULL and CHECK constraints.
  • Using the wrong extraction arrow: -> leaves the quotes on the string ("dark"). ->> removes the quotes (dark). If you query WHERE preferences->'theme' = 'dark', it will fail because you are comparing a JSON string to a SQL string. Always use ->> for WHERE comparisons.

10. Best Practices

  • Indexing JSONB (GIN Indexes): By default, searching inside a JSONB column forces a Full Table Scan. To make JSONB queries instant, you MUST create a GIN (Generalized Inverted Index) on the column.
CREATE INDEX idx
userprefs ON users USING GIN (preferences);

11. Exercises

  1. 1. What is the fundamental performance difference between the JSON and JSONB data types?
  1. 2. Which extraction operator (-> or ->>) returns raw text suitable for a WHERE clause comparison?

12. SQL Challenges

Assume you have a products table with a JSONB column named attributes. Write a query to select the product
name for all products where the attributes JSON contains a key named "color" with the exact value "red".
sql
123
SELECT product_name 
FROM products 
WHERE attributes->>'color' = 'red';

13. MCQ Quiz with Answers

Question 1

Why is the JSONB data type highly recommended over the standard JSON data type for production PostgreSQL databases?

Question 2

What type of Index must be applied to a JSONB column to allow PostgreSQL to rapidly search the deeply nested keys and arrays inside the payload without performing a Full Table Scan?

14. Interview Questions

  • Q: Explain the difference between the -> and ->> JSON extraction operators in PostgreSQL.
  • Q: Describe an architectural scenario where storing data in a JSONB column is vastly superior to normalizing that data into a strict, traditional relational table format.

15. FAQs

Q: Can I update just a single key inside a JSONB payload without overwriting the whole thing? A: Yes! PostgreSQL provides the jsonb_set() function, which allows you to surgically update a single key deep within the JSON object while leaving the rest of the payload untouched.

16. Summary

You are no longer bound by the rigid constraints of 1980s database theory. By wielding the JSONB data type, you can seamlessly blend the strict, transactional reliability of a Relational Database with the dynamic, schema-less flexibility of modern Document Databases.

17. Next Chapter Recommendation

Our database is perfectly structured, heavily optimized, and holding gigabytes of JSON data. What happens if the hard drive physically melts? Or what if you need to move the database to a new cloud server? In Chapter 24: Importing, Exporting, Backup, and Recovery, we will master the critical operational commands of a Database Administrator.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·