Databases: Comparison, Choosing & Polyglot
jsonb: Indexes, Tradeoffs & Exercise
jsonb is and why PostgreSQL stores it in binary formatjsonb instead of normal columnsjsonb column from Spring BootJdbcTemplateYou are building a books API for a library. The library has three types of books — novels, textbooks, and comics. Each type has completely different attributes.
This is a perfect use case for jsonb — instead of creating a messy table full of NULL columns, you store the flexible attributes in one jsonb column called details.
By the end of this page your API will:
books table with a jsonb column created automatically on startupGET /api/books endpoint that returns all booksjsonb?jsonb stands for JSON Binary. It is a PostgreSQL column type that stores a JSON value an object, array, string, or number in a binary format inside a regular relational table.
PostgreSQL offers two JSON column types:
| Type | Storage | Can be indexed? | Use this? |
|---|---|---|---|
json |
Raw text | No | Rarely |
jsonb |
Binary (parsed) | Yes — GIN index | Always |
Always use jsonb it is faster to query, supports indexing, and validates JSON on insert. If you insert invalid JSON, PostgreSQL rejects it immediately with an error. That is actually useful.
jsonb vs normalized tablesThis is the most important decision. jsonb solves a specific problem, use it only when that problem exists.
A library has three types of books novels, textbooks, and comics. Each type has completely different attributes. In a normal table you are forced to add a column for every possible attribute:
books table (bad approach - full of NULLs)
| id | title | genre | pages | subject | artist |
|---|---|---|---|---|---|
| 1 | The Hobbit | Fantasy | 310 | NULL | NULL |
| 2 | Clean Code | NULL | 431 | Software | NULL |
| 3 | Batman #1 | NULL | NULL | NULL | Miller |
Most columns are NULL for most rows. Adding a new book type means ALTER TABLE to add more columns.
jsonb solutionbooks table(good approach)
| id | title | details (jsonb) |
|---|---|---|
| 1 | The Hobbit | {"author": "Tolkien","genre":"Fantasy"} |
| 2 | Clean Code | {"author":"Martin","subject":"Software"} |
| 3 | Batman #1 | {"artist":"Miller","issue":"1"} |
No NULL columns. No schema change when you add a new book type.
Use jsonb when:
Use normal columns when:
NOT NULL, UNIQUE, or foreign key constraints<aside> 💡
The practical rule: put stable fields you always query (title) as proper columns. Put flexible varying fields (details) in jsonb.
</aside>
jsonb ColumnThere are two ways to create the table in Spring Boot. The recommended way is using a SQL file but both are shown here.

Open the IntelliJ terminal and check it is running:
docker ps
docker start my-postgres
docker exec -it my-postgres psql -U hyfuser -d postgres
CREATE DATABASE jsonb_demo;
\q
Go to start.spring.io:
| Setting | Value |
|---|---|
| Build system | Maven |
| Language | Java |
| Spring Boot | Latest stable |
| Group | net.hackyourfuture |
| Artifact | WeekNineJsonDemo |
| Packaging | jar |
| Java | 25 |
| Dependencies | Spring Web, JDBC API, PostgreSQL Driver, Lombok |
Click Generate, unzip, open in IntelliJ.
Add Jackson to pom.xml inside <dependencies>:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
application.yamlspring:
application:
name: WeekFourRestAPI
datasource:
url: jdbc:postgresql://localhost:5432/jsonb_demo
username: hyfuser
password: hyfpassword
sql:
init:
# runs schema.sql automatically every time the app starts
mode: always
In IntelliJ, right-click on src/main/resources → New → File → name it schema.sql.
Paste this inside:
CREATE TABLE IF NOT EXISTS books (
id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
details JSONB
);
CREATE TABLE IF NOT EXISTS means it only creates the table if it does not already exist — safe to run every time the app starts.
Notice the details column type is JSONB that is the only special part.
When you start the app, Spring Boot finds schema.sql automatically and runs it.
Use one approach only - either schema.sql or DatabaseInitializer, not both.
java
package net.hackyourfuture.WeekFourRestAPI;
import org.springframework.boot.CommandLineRunner;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class DatabaseInitializer implements CommandLineRunner {
private final JdbcTemplate jdbcTemplate;
public DatabaseInitializer(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void run(String... args) {
jdbcTemplate.execute("""
CREATE TABLE IF NOT EXISTS books (
id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
details JSONB
)
""");
System.out.println("Books table ready!");
}
}
bash
docker exec -it my-postgres psql -U hyfuser -d jsonb_demo