The document says:

jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing boolean])

In your example, the second parameter - '{k2,value}' is the search path, but since the first path is k2 that does not exist, results to NULL before value could be added/replaced.

In simple terms โ€“ jsonb_set is not meant to build entire JSON document the way you tried using search path, but to add or replace single key/value.

If you want to add/replace entirely new set of JSON like that you can use || (concatenate) operator instead like that:

-- Add example:
SELECT $${"k1": {"value": "v1"}}$$::jsonb || $${ "k2": { "value": "v2"}}$$::jsonb;
                    ?column?
------------------------------------------------
 {"k1": {"value": "v1"}, "k2": {"value": "v2"}}
(1 row)

-- Replace example
SELECT $${"k1": {"value": "v1"}}$$::jsonb || $${ "k1": { "value": "v2"}}$$::jsonb;
        ?column?
-------------------------
 {"k1": {"value": "v2"}}
(1 row) 

OR

You can use jsonb_set() like that instead:

SELECT JSONB_SET(
    '{"k1": {"value": "v1"}}',
    '{k2}',
    '{"value": "v2"}',
    TRUE
);
                   jsonb_set
------------------------------------------------
 {"k1": {"value": "v1"}, "k2": {"value": "v2"}}
(1 row)
Answer from Kristo Mรคgi on Stack Overflow
๐ŸŒ
Neon
neon.com โ€บ postgresql โ€บ json-functions โ€บ jsonb_set
PostgreSQL jsonb_set() Function
Therefore the jsonb_set() function changes the number 4 as the first element of the nested array [4,5] to 3. The following example uses the jsonb_set() to update the value of a key in a JSON object:
๐ŸŒ
pgPedia
pgpedia.info โ€บ j โ€บ jsonb_set.html
jsonb_set() - pgPedia - a PostgreSQL Encyclopedia
If path points to an item which does not exist, it will be inserted, unless create_if_missing is set to false: postgres=# SELECT jsonb_set('["foo","bar"]', '{2}', '"baz"'); jsonb_set ----------------------- ["foo", "bar", "baz"] (1 row) postgres=# SELECT jsonb_set('["foo","bar"]', '{2}', '"baz"', ...
๐ŸŒ
PostgreSQL
postgresql.org โ€บ docs โ€บ 9.5 โ€บ functions-json.html
PostgreSQL: Documentation: 9.5: JSON Functions and Operators
February 11, 2021 - Note: All the items of the path parameter of jsonb_set must be present in the target, unless create_missing is true, in which case all but the last item must be present.
๐ŸŒ
DEV Community
dev.to โ€บ deepika_banoth โ€บ how-to-use-jsonbset-function-in-postgresql-35eo
How to: use jsonb_set function in PostgreSQL - DEV Community
February 21, 2020 - jsonb_set(target jsonb, path text[], new_value jsonb, [create_missing boolean]) Returns target with the section designated by path replaced by new_value, or with new_value added if create_missing is true (default is true) and the item designated ...
๐ŸŒ
CommandPrompt Inc.
commandprompt.com โ€บ education โ€บ postgresql-jsonb_set-function
PostgreSQL JSONB_SET() Function โ€” CommandPrompt Inc.
August 14, 2023 - JSONB_SET() accepts a new value, a JSONB value, and a path as arguments, and inserts the new value at the specified path within the targeted JSONB value.
๐ŸŒ
Aaron Bos
aaronbos.dev โ€บ posts โ€บ update-json-postgresql
Updating JSON Data in PostgreSQL
March 20, 2021 - So this time we will attempt to run this. UPDATE public.person SET personb = jsonb_set_lax(personb, '{interests, 2}', NULL, true, 'not_an_option') WHERE personb ->> 'last_name' = 'Ellis';
Top answer
1 of 3
8

The document says:

jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing boolean])

In your example, the second parameter - '{k2,value}' is the search path, but since the first path is k2 that does not exist, results to NULL before value could be added/replaced.

In simple terms โ€“ jsonb_set is not meant to build entire JSON document the way you tried using search path, but to add or replace single key/value.

If you want to add/replace entirely new set of JSON like that you can use || (concatenate) operator instead like that:

-- Add example:
SELECT $${"k1": {"value": "v1"}}$$::jsonb || $${ "k2": { "value": "v2"}}$$::jsonb;
                    ?column?
------------------------------------------------
 {"k1": {"value": "v1"}, "k2": {"value": "v2"}}
(1 row)

-- Replace example
SELECT $${"k1": {"value": "v1"}}$$::jsonb || $${ "k1": { "value": "v2"}}$$::jsonb;
        ?column?
-------------------------
 {"k1": {"value": "v2"}}
(1 row) 

OR

You can use jsonb_set() like that instead:

SELECT JSONB_SET(
    '{"k1": {"value": "v1"}}',
    '{k2}',
    '{"value": "v2"}',
    TRUE
);
                   jsonb_set
------------------------------------------------
 {"k1": {"value": "v1"}, "k2": {"value": "v2"}}
(1 row)
2 of 3
6

I just faced the same issue and created a simple postgres-function for it. It may not be the fastest solution and might especially be slow for deep inserts, but so far works fine for me!

CREATE OR REPLACE FUNCTION jsonb_deep_set(curjson jsonb, globalpath text[], newval jsonb) RETURNS jsonb AS
$$
  BEGIN
    IF curjson is null THEN
      curjson := '{}'::jsonb;
    END IF;
    FOR index IN 1..ARRAY_LENGTH(globalpath, 1) LOOP
      IF curjson #> globalpath[1:index] is null THEN
        curjson := jsonb_set(curjson, globalpath[1:index], '{}');
      END IF;
    END LOOP;
    curjson := jsonb_set(curjson, globalpath, newval);
    RETURN curjson;
  END;
$$
LANGUAGE 'plpgsql';

Relacing jsonb with json makes it also work for json objects.

๐ŸŒ
Sqliz
sqliz.com โ€บ postgresql-ref โ€บ jsonb_set
PostgreSQL jsonb_set() Function
The PostgreSQL jsonb_set() function returns the given JSONB value with the specified path replaced with the new value, or insert the new value if create_if_missing is true (the default). If any parameter new_value is NULL, the jsonb_set() function will return NULL.
Find elsewhere
๐ŸŒ
Ankur Rathore
ankurrathore.net.in โ€บ posts โ€บ jsondb_postgresql
Updating JSONB Data in PostgreSQL ยท Ankur Rathore
September 15, 2024 - You can update nested fields by specifying a path in the format '{parent,child}'. For example: UPDATE my_table SET json_data = jsonb_set( json_data, '{parent,child}', '"new_nested_value"', true ) WHERE id = 1; To update multiple fields in a JSONB document, you can nest jsonb_set() calls: UPDATE ...
๐ŸŒ
Stanza
stanza.dev โ€บ courses โ€บ postgresql json & document processing โ€บ updating json with jsonb_set and jsonb_insert
Updating JSON with jsonb_set and jsonb_insert - PostgreSQL JSON & Document Processing | Stanza
-- Basic syntax jsonb_set(target, path, new_value, create_if_missing) -- Update existing key SELECT jsonb_set( '{"name": "Alice", "age": 30}'::jsonb, '{age}', '31' ); -- Result: {"age": 31, "name": "Alice"} -- Add new key SELECT jsonb_set( '{"name": ...
๐ŸŒ
Medium
mike-diaz006.medium.com โ€บ what-i-learned-at-work-this-week-update-json-property-in-postgres-4ac6a73335db
What I Learned at Work this Week: Update JSON Property in Postgres | by Mike Diaz | Medium
May 21, 2023 - Sort of like this: data = stuff_that_exists + something_new + rest_of_existing_data ยท Postgres has a couple of options for this in jsonb. First, we could use ||: update cards set data = data || '{"tags": ["CloudBees"]}';
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 74477665 โ€บ how-to-use-jsonb-set-with-with-as-variable
postgresql - How to use jsonb_set with "WITH AS" variable? - Stack Overflow
I am trying to use jsonb_set to change a single attribute of a jsonb object within my Postgres table. I am using WITH random_string AS to set the variable random_string to a random hexidecimal valu...
๐ŸŒ
freeCodeCamp
freecodecamp.org โ€บ news โ€บ how-to-update-objects-inside-jsonb-arrays-with-postgresql-5c4e03be256a
How to update objects inside JSONB arrays with PostgreSQL
April 15, 2019 - Fortunately, PostgreSQL is your friend and provides the _jsonbset function: _jsonb_set(target jsonb, path text[], new_value jsonb[, createmissing boolean])
๐ŸŒ
freeCodeCamp
freecodecamp.org โ€บ news โ€บ postgresql-and-json-use-json-data-in-postgresql
PostgreSQL and JSON โ€“ How to Use JSON Data in PostgreSQL
May 10, 2023 - For example, SELECT json_agg(my_column) FROM my_table; will return a JSON array containing the values in the "my_column" column of the "my_table" table. jsonb_set: This function updates a JSON object field with a new value.
๐ŸŒ
Beekeeper Studio
beekeeperstudio.io โ€บ blog โ€บ jsonb-functions-in-postgresql
Master JSONB Functions in PostgreSQL: A Practical Guide | Beekeeper Studio
August 24, 2025 - PostgreSQL provides additional ... LIMIT 1; -- Update a nested value using jsonb_set UPDATE users SET data = jsonb_set(data, '{address,zip}', '"10001"') WHERE data ?...
๐ŸŒ
GitHub
gist.github.com โ€บ villelahdenvuo โ€บ 5b1fbbf3f22853475bba14f8833faada
PostgreSQL jsonb_set is nice, but it does't create missing objects so I made this little helper. ยท GitHub
update "myTable" set "myField" = jsonb_set(COALESCE("myField", '{}'), '{"depth1"}', jsonb_set(COALESCE("myField"->'depth1', '{}'), '{"depth2"}', jsonb_set(COALESCE("myField"->'depth1'->'depth2', '{}'), '{"depth3"}', jsonb_set(COALESCE("myField"->'depth1'->'depth2'->'depth3', '{}'), '{"depth4"}', '"newValue"' )))) where "id" = 'myRowID' returning * Of course, this is somewhat of a pain if you're writing the query by hand; but it's useful to know about, in cases where you don't want to (or aren't able to) add a native PostgreSQL function to the database.