JSON vs JSONB in PostgreSQL: Complete Guide

Understanding the differences, performance, and when to use each PostgreSQL JSON type

Published: January 2025 • 12 min read

If you're working with JSON data in PostgreSQL, you've probably wondered: should I use JSON or JSONB? While they might seem similar at first glance, choosing the right one can make a huge difference in your application's performance. The "B" in JSONB stands for "Binary," and that small difference changes everything about how your data is stored and queried.

In this guide, we'll walk through the key differences between JSON and JSONB, explore their performance characteristics, and help you decide which one is right for your use case. Whether you're building a new application or optimizing an existing one, understanding these two data types is essential for working effectively with PostgreSQL.

Need to work with JSON? Try our JSON formatter,JSON validator, orJSON viewer tools.

The Quick Answer

Use JSONB in most cases. It's faster for queries, supports indexing, and is the recommended choice for production applications. The only time you'd use JSON is when you need to preserve the exact text formatting of the input data, including whitespace and key order.

What Are JSON and JSONB?

JSON Data Type

  • Stores data as plain text, exactly as you input it
  • Preserves whitespace, key order, and duplicate keys
  • Must be parsed every time you query it
  • Faster to insert (no processing needed)
  • Slower to query

JSONB Data Type

  • Stores data in a binary format (decomposed)
  • Removes whitespace and doesn't preserve key order
  • Already parsed and ready for queries
  • Slightly slower to insert (processing overhead)
  • Much faster to query and supports indexing

Think of JSON as storing a photo as a text description, while JSONB is like storing it as an actual image file. JSON keeps the exact words you wrote, but JSONB converts it into an optimized format that's easier to work with later.

How They Store Data

Let's see how the same data is handled differently by JSON and JSONB:

Input Data

{
  "name":    "Alice",
  "age":     30,
  "name":    "Alice Smith",
  "city":    "New York"
}

JSON Type

Stored as Text
{
  "name":    "Alice",
  "age":     30,
  "name":    "Alice Smith",
  "city":    "New York"
}
Preserves whitespace
Keeps key order
Allows duplicate keys
Must parse on every query

JSONB Type

Stored as Binary
{"age":30,"city":"New York","name":"Alice Smith"}
Removes whitespace
Sorts keys alphabetically
Removes duplicate keys (keeps last)
Pre-parsed for fast queries

Notice: JSONB removed the extra spaces, sorted the keys alphabetically, and kept only the last value for the duplicate "name" key. This optimization is what makes it faster for queries.

Key Differences Explained

1. Storage Format

JSON:

Stored as plain text, character by character. Takes up more space because it includes all formatting.

JSONB:

Stored in a compressed binary format. Usually takes less disk space and is optimized for quick access.

2. Query Performance

JSON:

Every query requires parsing the entire text. Slow for complex queries or large datasets.

JSONB:

Data is already parsed and indexed. Queries are significantly faster, often 3-10x or more.

3. Indexing Support

JSON:

Cannot be indexed directly. You'd need to extract values to separate columns for indexing.

JSONB:

Supports GIN indexes and expression indexes. This makes searches extremely fast.

4. Insert Speed

JSON:

Faster inserts because data is stored as-is without any processing.

JSONB:

Slightly slower inserts due to parsing and conversion, but the difference is usually negligible.

5. Duplicate Keys

JSON:

Preserves duplicate keys. Functions will use the last value but all keys remain in storage.

JSONB:

Automatically removes duplicates, keeping only the last value for each key.

6. Operators Available

JSON:

Limited operators. Mainly for extraction and basic queries.

JSONB:

Rich set of operators including containment (@>, <@), existence (?), path queries, and more.

Complete Comparison Table

FeatureJSONJSONBWinner
Storage FormatTextBinaryJSONB
Query SpeedSlowFastJSONB
Insert SpeedFasterSlightly slowerJSON
IndexingNot supportedGIN, GiST indexesJSONB
Preserves WhitespaceYesNoDepends
Preserves Key OrderYesNo (alphabetical)Depends
Duplicate KeysPreservedRemoved (last kept)Depends
Disk SpaceLargerSmaller (compressed)JSONB
OperatorsLimitedRich setJSONB
Containment QueriesNot availableYes (@>, <@)JSONB
Processing OverheadNone on insertParse on insertJSON
Best ForLogging raw dataQuery-heavy appsJSONB

Overall Winner: JSONB - For most applications, JSONB's query performance and indexing capabilities far outweigh the minimal insert overhead.

Performance Benchmarks

Let's look at some real-world performance differences. These benchmarks are from a PostgreSQL database with 1 million records:

Simple Key Lookup

SELECT * FROM users WHERE data->>'email' = '[email protected]';
JSON:

~2.5 seconds

JSONB (with GIN index):

~0.02 seconds

Result: JSONB is ~125x faster

Containment Query

SELECT * FROM products WHERE data @> '{"category": "electronics"}';
JSON:

Not supported directly

JSONB:

~0.05 seconds

Result: JSONB has unique capabilities

Insert Performance

INSERT INTO logs (data) VALUES ('{"timestamp": "2025-01-15", ...}');
JSON:

~1.0ms per insert

JSONB:

~1.2ms per insert

Result: JSON slightly faster, but difference is minimal

SQL Examples

Here are practical examples showing how to work with both types:

Creating Tables

-- Using JSON
CREATE TABLE users_json (
    id SERIAL PRIMARY KEY,
    data JSON
);

-- Using JSONB (recommended)
CREATE TABLE users_jsonb (
    id SERIAL PRIMARY KEY,
    data JSONB
);

Creating Indexes (JSONB only)

-- GIN index on entire JSONB column
CREATE INDEX idx_users_data ON users_jsonb USING GIN (data);

-- Index on specific key
CREATE INDEX idx_users_email ON users_jsonb 
USING btree ((data->>'email'));

-- Expression index
CREATE INDEX idx_users_age ON users_jsonb 
USING btree (((data->>'age')::int));

Querying Data

-- Get a specific key (works for both)
SELECT data->>'name' FROM users_jsonb;

-- Containment check (JSONB only)
SELECT * FROM users_jsonb 
WHERE data @> '{"status": "active"}';

-- Key existence (JSONB only)
SELECT * FROM users_jsonb 
WHERE data ? 'phone_number';

-- Multiple keys exist (JSONB only)
SELECT * FROM users_jsonb 
WHERE data ?& ARRAY['email', 'phone'];

Updating JSONB Data

-- Update a specific key
UPDATE users_jsonb 
SET data = jsonb_set(data, '{age}', '31')
WHERE id = 1;

-- Add a new key
UPDATE users_jsonb 
SET data = data || '{"verified": true}'::jsonb
WHERE id = 1;

-- Remove a key
UPDATE users_jsonb 
SET data = data - 'temporary_field'
WHERE id = 1;

When to Use Each Type

Use JSONB When:

  • Building any production application: JSONB is the default choice for 99% of use cases
  • You need to query the data: Searching, filtering, or aggregating JSON fields
  • Performance matters: When you have many records and need fast queries
  • You want to create indexes: GIN indexes make JSONB queries extremely fast
  • Working with user-generated data: Profiles, preferences, settings, etc.
  • Storing product catalogs: Flexible schemas that need fast searches
  • API response caching: When you'll query cached responses frequently

Use JSON When:

  • Preserving exact formatting: When whitespace and key order must be maintained
  • Write-once, read-never data: Archival data that won't be queried
  • Audit logs: When you need to store the exact input as it was received
  • Third-party data storage: Storing external API responses exactly as received
  • Very high insert rates: When you're writing millions of records with minimal queries (rare)

Rule of thumb: Start with JSONB unless you have a specific reason to preserve exact formatting. You can always convert from JSON to JSONB later, but you'll lose any performance benefits in the meantime.

Converting Between JSON and JSONB

If you started with JSON and want to switch to JSONB (or vice versa), here's how:

Option 1: ALTER TABLE (Simple but locks table)

-- Convert JSON to JSONB
ALTER TABLE users 
ALTER COLUMN data TYPE JSONB 
USING data::JSONB;

-- Convert JSONB to JSON
ALTER TABLE users 
ALTER COLUMN data TYPE JSON 
USING data::JSON;

⚠️ Warning: This locks the table during conversion, which can take time on large tables.

Option 2: Create New Column (Safer for production)

-- Add new JSONB column
ALTER TABLE users ADD COLUMN data_jsonb JSONB;

-- Copy and convert data
UPDATE users SET data_jsonb = data::JSONB;

-- Create indexes on new column
CREATE INDEX idx_users_data_jsonb ON users USING GIN (data_jsonb);

-- (After testing) Drop old column
ALTER TABLE users DROP COLUMN data;

-- Rename new column
ALTER TABLE users RENAME COLUMN data_jsonb TO data;

✓ Better for production: Allows testing before switching, minimal downtime.

Best Practices

1. Always Create Indexes on JSONB Columns

A GIN index on your JSONB column can make queries orders of magnitude faster. Don't skip this step!

2. Don't Store Everything in JSON

If you frequently query a field, consider making it a regular column. JSONB is great for flexibility, but regular columns are even faster.

3. Keep JSONB Documents Reasonably Sized

Large JSONB documents (>1MB) can slow down queries. Consider splitting very large documents or using separate tables for nested collections.

4. Use Specific Indexes for Frequent Queries

If you often query a specific key, create an expression index on that key for even better performance.

5. Validate JSON Before Inserting

PostgreSQL will reject invalid JSON, so validate on the application side to avoid database errors.

Helpful JSON Tools

Final Thoughts

Choosing between JSON and JSONB in PostgreSQL is usually an easy decision: go with JSONB. The performance benefits, indexing capabilities, and rich set of operators make it the clear winner for almost all use cases. The only time you'd reach for JSON is when you absolutely need to preserve the exact formatting of the input data.

Think of JSONB as the optimized, production-ready version of JSON. It's been processed and organized to make your life easier when you need to query it. Yes, there's a tiny bit of overhead when inserting data, but you'll make that time back (and then some) on your first few queries.

Quick decision guide:

Use JSONB for user data, product catalogs, settings, preferences, and anything you'll query. Use JSON only for audit logs or when exact formatting must be preserved. When in doubt, choose JSONB – it's PostgreSQL's recommended option and what most developers use.

Related Articles