This post takes a closer look at some of the most impactful features we have shipped in CedarDB across our recent releases. Whether you have been following along closely or are just catching up, here is a deeper look at the additions we are most excited about.

Set-Returning Functions: Lock-Step Evaluation

v2026-04-20

When handling bulk data transformations or speeding up database inserts, a popular developer trick is to use multiple set-returning functions side-by-side in the SELECT clause to “zip” arrays together into individual rows. To improve performance and scalability, PostgreSQL changed its behavior regarding this in version 10, shifting from generating a massive cross-product to a much more efficient lock-step evaluation (see the PostgreSQL 10 Release Notes).

To guarantee seamless compatibility and keep your queries lightning-fast, CedarDB evaluates multiple set-returning functions in the SELECT list in the exact same lock-step manner.

-- Zipping up arrays in lock-step to quickly generate rows
SELECT UNNEST('{alice, bob, charlie}'::TEXT[]) AS user_name, 
       UNNEST('{active, inactive, active}'::TEXT[]) AS status, 
       UNNEST('{150, 200, 350}'::INT[]) AS score;

Instead of exploding into 27 rows of useless, cross-joined data, CedarDB cleanly steps through the arrays row-by-row to return exactly 3 perfectly paired rows. If you rely on array unnesting to batch your application’s database inserts, you can now enjoy highly scalable performance and behavior that is completely identical to modern PostgreSQL.

Note: This lock-step evaluation applies to other set-returning functions you might already know! Alongside UNNEST, you can use functions like generate_series, json_array_elements, or regexp_matches to efficiently generate and zip your data.

ON UPDATE CASCADE: Keep Your Data in Sync Automatically

v2026-04-20

Changing core identifiers, like a user’s handle or a department code, used to mean manually updating every referencing row to avoid breaking foreign key constraints. To make your life easier, CedarDB now supports ON UPDATE CASCADE. Just add this clause to your foreign key, and CedarDB will automatically propagate updates from the parent table directly to its child tables.

Say you have a platform where posts reference an author’s username. If an author changes their handle, a single UPDATE handles the rest:

CREATE TABLE authors (username TEXT PRIMARY KEY);

CREATE TABLE posts (
    post_id INTEGER PRIMARY KEY,
    created_at TIMESTAMP,
    author_username TEXT REFERENCES authors(username) ON UPDATE CASCADE
);

-- Updating 'alice' to 'alice_smith' automatically updates all her posts!
UPDATE authors SET username = 'alice_smith' WHERE username = 'alice';

Note: To guarantee predictable performance and prevent runaway loops, CedarDB currently limits this to single-level cascades. An auto-updated column cannot act as the trigger for another cascade into a third table. CedarDB validates this at table creation time, so your schema stays consistent and performant.

pg_stat_database and pg_stat_activity: Observability Out of the Box

v2026-04-20

CedarDB now implements pg_stat_database and pg_stat_activity, two of Postgres’ most widely used monitoring tables. This means your existing observability stack (pgAdmin, Datadog, or any custom dashboard that speaks Postgres) just works with CedarDB, no changes required.

pg_stat_activity gives you a live window into what your database is doing right now: active queries, connection states, and client details. Spot long-running idle transactions that are holding locks or causing WAL bloat:

SELECT pid, usename, state, xact_start, now() - xact_start AS idle_duration
FROM pg_stat_activity
WHERE state = 'idle in transaction'
  AND now() - xact_start > interval '5 minutes';

pg_stat_database complements this with per-database aggregate statistics: transactions committed and rolled back, cache hit rates, tuples returned, and more. To check your database health at a glance:

SELECT datname,
       blks_hit::float / nullif(blks_hit + blks_read, 0) AS cache_hit_ratio,
       xact_commit,
       xact_rollback
FROM pg_stat_database
WHERE datname = current_database();

VACUUM (TRUNCATE): Release Disk Space Back to the OS

v2026-04-20

CedarDB’s storage footprint grows as your data grows, but until now, the main storage file never shrank. Dropped indexes, truncated tables, and deleted data all freed up pages internally, but the underlying file stayed the same size on disk. In some cases this could leave you with a much larger file than your actual data warrants, for example after building and then dropping a large index, or after rewriting ALTER operations.

VACUUM (TRUNCATE) addresses the most straightforward case: if there are unused pages at the end of the storage file, CedarDB will truncate the file and return that space to the OS.

-- After dropping a large index or table, reclaim the trailing space
VACUUM (TRUNCATE);

CedarDB also now properly returns pages to the free pool after ALTER TABLE and ALTER INDEX statements, making them eligible for truncation. More comprehensive shrinking behavior, covering space freed in the middle of the file, will follow in future releases.

Note: Only trailing unused pages can be released to the OS today. Freed space in the middle of the file is currently retained for reuse by future writes.

json_agg and json_build_array: JSON Aggregation in SQL

v2026-04-27

Two commonly used JSON aggregation functions are now available in CedarDB: json_agg and json_build_array.

json_agg aggregates rows into a JSON array, which makes it straightforward to produce nested JSON results directly from a query. This is useful for building API responses or feeding data to applications that expect JSON without an extra serialization step:

-- Return each author with a JSON array of their post titles
SELECT a.username,
       json_agg(p.title ORDER BY p.created_at DESC) AS recent_posts
FROM authors a
JOIN posts p ON p.author_username = a.username
GROUP BY a.username;

json_build_array lets you construct a JSON array from explicit values or column references in a single row:

SELECT json_build_array(user_id, username, email) AS user_tuple
FROM users
LIMIT 5;

Together, these two functions cover the most common patterns for producing JSON output directly in SQL, without needing to post-process results in application code.


That’s it for now


Questions or feedback? Join us on Slack or reach out directly.

Do you want to try CedarDB straight away? Sign up for our free Enterprise Trial below. No credit card required.