HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
citusdata
cstore_fdw
C2014–2024
citusdata / cstore_fdw

cstore_fdw

Columnar storage extension for Postgres built as a foreign data wrapper. Check out https://github.com/citusdata/citus for a modernized columnar storage implementation built as a table access method.

33Distinct people
36Mentions
0Explicit recommenders
1.8KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Columnar storage extension for Postgres built as a foreign data wrapper. Check out https://github.com/citusdata/citus for a modernized columnar storage implementation built as a table access method.

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 1:49:46 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year36 dated mentions

Observed mentions: 2014-04-03 19:21:05 UTC to 2024-02-22 06:09:13 UTC.

02462014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 7 mentions; 0 submissions, 7 comments20142015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 7 mentions; 1 submissions, 6 comments2016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 5 mentions; 2 submissions, 3 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 5 mentions; 1 submissions, 4 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments20192020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2024

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20142014-01-01 00:00:00 UTC2015-01-01 00:00:00 UTC707
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC716
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC523
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC514
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC101
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC101
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC505
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC000
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC303
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC101
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC101

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
Important notice: Columnar storage is now part of Citus Columnar storage is now part of the Citus extension, which uses the table access method API to give a much more native experience. It also supports streaming replication, archival, rollback, and simplifies pg_upgrade. You can use Citus just for columnar storage on a single PostgreSQL server, or combine it with distributed tables to parallelize queries locally or across a cluster of PostgreSQL servers. Migration is simple, and you'll typically see improved compression thanks to zstd: -- After adding adding shared_preload_libraries = 'citus' -- to postgresql.conf and restarting: CREATE EXTENSION IF NOT EXISTS citus; -- Create a table using the columnar access method, with the same columns -- as an existing cstore_fdw table CREATE TABLE customer_reviews_am ( LIKE customer_reviews_fdw INCLUDING ALL ) USING columnar; -- Copy data from an old cstore_fdw table to an access method table INSERT INTO customer_reviews_am SELECT * FROM customer_reviews_fdw; -- cstore_fdw data size SELECT pg_size_pretty(cstore_table_size('customer_reviews_fdw')); ┌────────────────┐ │ pg_size_pretty │ ├────────────────┤ │ 100 MB │ └────────────────┘ -- Citus Columnar data size SELECT pg_size_pretty(pg_table_size('customer_reviews_am')); ┌────────────────┐ │ pg_size_pretty │ ├────────────────┤ │ 64 MB │ └────────────────┘ Read more about it in the Citus columnar blog post by Jeff Davis. cstore_fdw Cstore_fdw is an open source columnar store extension for PostgreSQL. Columnar stores provide notable benefits for analytics use cases where data is loaded in batches. Cstore_fdw’s columnar nature delivers performance by only reading relevant data from disk, and it may compress data 6x-10x to reduce space requirements for data archival. Cstore_fdw is developed by Citus Data and can be used in combination with Citus, a postgres extension that intelligently distributes your data and queries across many nodes so your database can scale and your queries are fast. If you have any questions about how Citus can help you scale or how to use Citus in combination with cstore_fdw, please let us know. Join the Mailing List to stay on top of the latest developments for Cstore_fdw. Introduction This extension uses a format for its data layout that is inspired by ORC, the Optimized Row Columnar format. Like ORC, the cstore format improves upon RCFile developed at Facebook, and brings the following benefits: Compression: Reduces in-memory and on-disk data size by 2-4x. Can be extended to support different codecs. Column projections: Only reads column data relevant to the query. Improves performance for I/O bound queries. Skip indexes: Stores min/max statistics for row groups, and uses them to skip over unrelated rows. Further, we used the Postgres foreign data wrapper APIs and type representations with this extension. This brings: Support for 40+ Postgres data types. The user can also create new types and use them. Statistics collection. PostgreSQL's query optimizer uses these stats to evaluate different query plans and pick the best one. Simple setup. Create foreign table and copy data. Run SQL. Building cstore_fdw depends on protobuf-c for serializing and deserializing table metadata. So we need to install these packages first: # Fedora 17+, CentOS, and Amazon Linux sudo yum install protobuf-c-devel # Ubuntu 10.4+ sudo apt-get install protobuf-c-compiler sudo apt-get install libprotobuf-c0-dev # Ubuntu 18.4+ sudo apt-get install protobuf-c-compiler sudo apt-get install libprotobuf-c-dev # Mac OS X brew install protobuf-c Note. In CentOS 5, 6, and 7, you may need to install or update EPEL 5, 6, or 7 repositories. See this page for instructions. Note. In Amazon Linux, the EPEL repository is installed by default, but not enabled. See these instructions for how to enable it. Once you have protobuf-c installed on your machine, you are ready to build cstore_fdw. For this, you need to include the pg_config directory path in your make command. This path is typically the same as your PostgreSQL installation's bin/ directory path. For example: PATH=/usr/local/pgsql/bin/:$PATH make sudo PATH=/usr/local/pgsql/bin/:$PATH make install Note. cstore_fdw requires PostgreSQL version from 9.3 to 12. It doesn't support earlier versions of PostgreSQL. Usage Before using cstore_fdw, you need to add it to shared_preload_libraries in your postgresql.conf and restart Postgres: shared_preload_libraries = 'cstore_fdw' # (change requires restart) The following parameters can be set on a cstore foreign table object. filename (optional): The absolute path to the location for storing table data. If you don't specify the filename option, cstore_fdw will automatically choose the $PGDATA/cstore_fdw directory to store the files. If specified the value of this parameter will be used as a prefix for all files created to store table data. For example, the value /cstore_fdw/my_table could result in the files /cstore_fdw/my_table and /cstore_fdw/my_table.footer being used to manage table data. compression (optional): The compression used for compressing value streams. Valid options are none and pglz. The default is none. stripe_row_count (optional): Number of rows per stripe. The default is 150000. Reducing this decreases the amount memory used for loading data and querying, but also decreases the performance. block_row_count (optional): Number of rows per column block. The default is 10000. cstore_fdw compresses, creates skip indexes, and reads from disk at the block granularity. Increasing this value helps with compression and results in fewer reads from disk. However, higher values also reduce the probability of skipping over unrelated row blocks. To load or append data into a cstore table, you have two options: You can use the COPY command to load or append data from a file, a program, or STDIN. You can use the INSERT INTO cstore_table SELECT ... syntax to load or append data fr
Read the full README on GitHub

What Hacker News says

36 sources
Another similar option is cstore_fdw [0] -- it's now part of Citus but can still be used standalone as a foreign data wrapper. We use it at my startup to do OLAP on Postgres. It has some advantages on parquet_fdw: * Supports writes (actually generating Parquet files was also difficult in my testing: I used odbc2parquet [1] but thanks for the ogr2ogr tip!) so you can write directly to the foreign table by running INSERT INTO ... SELECT FROM ... * Supports all PG datatypes (including types from extensions, like PostGIS) * Performance was basically comparable in my limited testing (faster for a single-row SELECT with cstore_fdw in our case since we do partition pruning, same for a full-table scan-and-aggregation). Re: performance overhead, with FDWs we have to re-munge the data into PostgreSQL's internal row-oriented TupleSlot format again.
Read the rest
Postgres also doesn't run aggregations that can take advantage of the columnar format (e.g. CPU vectorization). Citus had some experimental code to get that working [2], but that was before FDWs supported aggregation pushdown. Nowadays it might be possible to basically have an FDW that hooks into the GROUP BY execution and runs a faster version of the aggregation that's optimized for columnar storage. We have a blog post series [3] about how we added agg pushdown support to Multicorn -- similar idea. There's also DuckDB which obliterates both of these options when it comes to performance. In my (again limited, not very scientific) benchmarking of on a customer's 3M row table [4] (278MB in cstore_fdw, 140MB in Parquet), I see a 10-20x (1/2s -> 0.1/0.2s) speedup on some basic aggregation queries when querying a Parquet file with DuckDB as opposed to using cstore_fdw/parquet_fdw. I think the dream is being able to use DuckDB from within a FDW as an OLAP query engine for PostgreSQL. duckdb_fdw [5] exists, but it basically took sqlite_fdw and connected it to DuckDB's SQLite interface, which means that a lot of operations get lost in translation and aren't pushed down to DuckDB, so it's not much better than plain parquet_fdw. I had a complex query in the PG dialect generated with dbt that used joins, CTEs and window functions. I don't remember the exact timings, but it was even slower on duckdb_fdw than with cstore_fdw, whereas I could take the same query and run it on DuckDB verbatim, only replacing the foreign table name with the Parquet filename. This comment is already getting too long, but FDWs can indeed participate in partitions! There's this blog post that I keep meaning to implement where the setup is, a "coordinator" PG instance has a partitioned table, where each partition is a postgres_fdw foreign table that proxies to a "data" PG instance. The "coordinator" node doesn't store any data and only gathers execution results from the "data" nodes. In the article, the "data" nodes store plain old PG tables, but I don't think there's anything preventing them from being parquet_fdw/cstore_fdw tables instead. [0] https://github.com/citusdata/cstore_fdw [1] https://github.com/pacman82/odbc2parquet [2] https://github.com/citusdata/postgres_vectorization_test [3] https://www.splitgraph.com/blog/postgresql-fdw-aggregation-p... [4] https://www.splitgraph.com/trase/supply-chains [5] https://github.com/alitrack/duckdb_fdw [6] https://swarm64.com/post/scaling-elastic-postgres-cluster/
In Postgres and Parquet in the data lake
The Splitgraph core code on GitHub [0], around which we've built the DDN, is all about managing "data images" which are basically snapshots of PostgreSQL schemata. You can build them with a format similar to Dockerfiles as well as do a "checkout" into a local instance of Splitgraph (which you can connect to with any PG client) -- this enables change tracking and delta compression too. Behind the scenes, we store them as cstore_fdw [2] files which is a columnar storage format that helps with analytical queries. [0] https://github.com/splitgraph/splitgraph/ [1] https://splitgraph.com/docs/concepts/images [2] https://github.com/citusdata/cstore_fdw
In The Splitgraph Data Delivery Network – query over 40k public datasets

Showing the 15 most recent of 36 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.