
Apache ORC
A columnar file format born in Hive: typed columns in large stripes, built-in indexes every 10,000 rows, and the storage behind Hive’s ACID tables.
- What it is
- File formats (columnar files)
- Type
- Open source
- Made by
- Apache Software Foundation
- License
- Apache 2.0
- Facts checked
- 6 October 2026
What it is
An ORC file starts with the bytes ORC, then a body of stripes, then a tail. Each stripe holds whole rows, about 64 MB of them by default in the Java writer, and is self-contained: an index section, the row data with every column stored separately, and a stripe footer. Writers pick encodings by type (dictionary, run-length, bit packing, delta) and then compress with ZLIB, Snappy, LZ4 or ZSTD, which the Java writer now uses by default. The tail holds the schema, the list of stripes and statistics for every column, in Protocol Buffers so new fields don’t break old readers, plus a small uncompressed postscript that says how to read the rest. A reader fetches the last 16 KB of the file first and works backwards.
Indexes sit at three levels: the whole file, each stripe, and each group of 10,000 rows inside a stripe. They record counts, nulls, minimum and maximum, and sums for numbers, and columns can add bloom filters. An engine turns a filter such as age > 100 into a search argument and skips files, stripes and row groups that can’t match. Hive builds ACID tables on ORC: updates and deletes go into delta directories of ORC files with extra columns (operation, original transaction, bucket, row id), and compactions merge them into new base files. ORC started in Hive in 2013 and became a top-level Apache project in 2015; it’s free under Apache 2.0, with Java and C++ libraries, and 2.3.1 (July 2026) is the current release.
Why teams pick it
- Indexes per file, stripe and 10,000-row group, plus optional bloom filters, let engines skip most of a file on selective queries
- A full set of typed columns, including decimal,
unionand two timestamp types, with the schema stored in the file - The format behind Hive’s full ACID tables (
UPDATE,DELETE,MERGE) and streaming ingest - Column-level encryption in the format, supported by Spark since 3.2
- The default format for new tables in the Hive connectors of Trino and Presto
Watch out for
- A smaller ecosystem than Parquet: Iceberg and Spark default to Parquet, and Delta Lake stores only Parquet
- Files are written once; Hive’s updates pile up delta files that need compaction, and ACID is built for millions of rows per transaction, not millions of transactions an hour
- ACID tables are a Hive feature, not part of the format, so other engines have to implement Hive’s transaction rules to read them correctly
- Some engines only read it: Impala can query ORC tables but can’t write them
- Two timestamp types: plain
timestamphas no time zone and shows the same wall-clock time everywhere, so ORC’s docs recommendtimestamp with local time zoneunless everything is in UTC
Alternatives
What all columnar files have in common →
PuffinOpen sourceApache Iceberg’s file format for the data that doesn’t fit in a manifest: a container of typed binary blobs, such as distinct-value sketches and deletion vectors, described by a JSON footer.
VortexOpen sourceA columnar file format and toolkit that keeps data compressed with modern encodings, reads single rows fast and runs filters directly on the compressed data, pitched as a faster successor to Parquet.How it fits with other technologies
What Apache ORC uses
A Hive ACID table on ORC, with ZSTD and a bloom filter · sql
-- Hive: transactions need the DbTxnManager and concurrency support
SET hive.support.concurrency=true;
SET hive.txn.manager=org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
CREATE TABLE orders (
order_id BIGINT,
customer_id BIGINT,
status STRING,
amount DECIMAL(10,2)
)
STORED AS ORC
TBLPROPERTIES (
'transactional' = 'true',
'orc.compress' = 'ZSTD',
'orc.bloom.filter.columns' = 'customer_id'
);
INSERT INTO orders VALUES (1, 42, 'new', 19.99), (2, 7, 'new', 5.00);
-- written as a delta directory; compaction later folds it into the base
UPDATE orders SET status = 'shipped' WHERE order_id = 1;
-- stripes and 10,000-row groups whose stats or bloom filter rule out 42 are skipped
SELECT order_id, status FROM orders WHERE customer_id = 42;ORC or Parquet?#
Both are open columnar formats from early 2013 with similar ideas: columns stored apart, statistics in a footer, files written once. The differences are in the details and, above all, in who supports them.
| ORC | Parquet | |
|---|---|---|
| Started by | Hortonworks with Facebook, to speed up Hive (January 2013) | Twitter and Cloudera, for any Hadoop engine (March 2013) |
| Unit of work | Stripes; 64 MB by default in the Java writer | Row groups; the docs suggest 512 MB to 1 GB |
| Built-in skipping | Count, nulls, min, max (and sum for numbers) per file, stripe and 10,000 rows; optional bloom filters | Min and max per column chunk; optional page index and bloom filters |
| Nested data | A child column per struct field, list element and map key and value; also a union type | Repetition and definition levels from Google’s Dremel paper |
| Footer encoding | Protocol Buffers | Thrift |
| Row updates | Hive’s full ACID tables (base and delta files); Hive implements them only for ORC | None in the format; use a table format such as Iceberg or Delta Lake |
| Table formats | Supported by Iceberg; not by Delta Lake | Iceberg’s default; Delta Lake’s only data file format |
| Default for new tables in | Hive connectors of Trino and Presto | Spark SQL |
- From each project’s own docs and specs, checked 2026-10-06. Spark’s default comes from
spark.sql.sources.default; Trino’s fromhive.storage-format.
See it in a real stack
No architecture uses Apache ORC yet. Drop it into the playground and wire it up yourself.Open playground →Where it came from2013–2026
For several years RCFile, a hybrid columnar format developed at Facebook, had been the standard way to store Hive tables on Hadoop. It kept each column value as an untyped binary blob. That meant whole values had to be read and decoded, filters couldn’t be pushed down to the file, and the file didn’t even know its row types. In January, Hortonworks co-founder Owen O’Malley opened HIVE-3874 to create an Optimized Row Columnar format, working with Facebook as part of Hortonworks’ Stinger initiative to make Hive up to 100 times faster.
ORC shipped in Hive 0.11 in May 2013, and the v1 file format still in use arrived with Hive 0.12 that October. Facebook ran its own ORC writer and reported in 2014 that switching tens of petabytes from RCFile raised compression from 5x to 8x. Hive 0.14 added ACID updates, implemented only for ORC. In April 2015 ORC became its own top-level Apache project. ORC 1.0 followed in January 2016, and from 1.1 Hadoop jobs could use ORC without pulling in Hive’s execution jar.
Why it’s built this way
- Keep the column types in the file
- RCFile stored blobs, so it couldn’t use type-specific compression or evaluate filters. ORC writes with type-aware encoders (dictionary, bit packing, delta, run-length) and stores the schema.
- Light indexes every 10,000 rows
- Minimum and maximum values for each column in each group of rows let Hive’s pushed-down filters skip whole groups without reading them.
- Tail at the end, metadata in Protocol Buffers
- HDFS files can’t be changed after they’re written, so the top-level index goes last. Protocol Buffers let later versions add fields without breaking older readers.
- Large, self-contained stripes
- Each stripe can be read with only its own bytes plus the file tail, which makes stripes the natural unit of work for distributed tasks.
Timeline
- 2013
HIVE-3874 opened in January; ORC ships in Hive 0.11 in May
- 2014
Facebook reports tens of PB moved to ORC; Hive 0.14 adds ACID on ORC
- 2015
Becomes a top-level Apache project in April
- 2016
ORC 1.0 released as a standalone library (January)
- 2024
ORC 2.0.0 released (March)
- 2026
ORC 2.3.1, the current release (July)
- HIVE-3874: Create a new Optimized Row Columnar file format for Hive (Owen O’Malley, January 2013)
- Hortonworks blog: The Stinger Initiative, ORCFile built with Facebook (February 2013) · archived copy, original
- Facebook Engineering: Scaling the Facebook data warehouse to 300 PB (April 2014)
- Apache Hive downloads: 0.11.0 (15 May 2013), 0.12.0 (15 October 2013), 0.14.0 (12 November 2014)
- ASF board minutes, 22 April 2015: Establish the Apache ORC Project
- Apache ORC releases (1.0.0 January 2016, 2.0.0 March 2024, 2.3.1 July 2026)
Sources28 · facts checked 6 October 2026
- Apache ORC docs: Background (stripes of about 64 MB, 10,000-row index groups)
- Apache ORC specification v1 (file tail, postscript, Protocol Buffers, stripes, compression kinds)
- Apache ORC specification versions (v0 in Hive 0.11, v1 in Hive 0.12)
- Apache ORC docs: Indexes (file, stripe and row-level statistics, bloom filters)
- Apache ORC docs: Types (including union and two timestamp types)
- Apache ORC docs: ACID support (base and delta files, not designed for OLTP)
- Apache ORC docs: Hive configuration (orc.compress defaults to ZSTD, orc.stripe.size, orc.row.index.stride)
- Apache ORC docs: Hive DDL (STORED AS ORC, CONCATENATE)
- Apache ORC docs: Adopters (Hive, Spark, Impala, Pig, Trino, Iceberg and more)
- Apache ORC releases (2.3.1, 16 July 2026)
- apache/orc LICENSE (Apache 2.0)
- Apache Hive docs: ACID Transactions (only ORC is supported; required settings)
- Spark docs: ORC files (native reader, ZSTD, bloom filters, columnar encryption since 3.2)
- Spark docs: Generic load/save functions (default data source is parquet)
- Trino docs: Hive connector (hive.storage-format defaults to ORC)
- Presto docs source: Hive connector (supported file types; hive.storage-format defaults to ORC)
- Impala docs: Using the ORC file format (query yes, INSERT no)
- Apache Pig docs: Built-in functions (OrcStorage)
- Iceberg table spec (data files in Avro, ORC or Parquet)
- Iceberg docs: Configuration (write.format.default is parquet)
- Delta transaction log protocol (Parquet data files)
- Apache Parquet docs: File format (Thrift metadata)
- Apache Parquet docs: Configurations (row groups of 512 MB to 1 GB)
- Apache Parquet docs: Motivation (record shredding from the Dremel paper)
- Apache Parquet docs: Nested encoding (definition and repetition levels)
- Apache Parquet docs: Page index
- Apache Parquet docs: Bloom filter
- Introducing Parquet: Twitter and Cloudera announcement (hdfs-user list, 12 March 2013)