Cloud Parts

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
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, union and 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 timestamp has no time zone and shows the same wall-clock time everywhere, so ORC’s docs recommend timestamp with local time zone unless everything is in UTC

Alternatives

What all columnar files have in common →

How it fits with other technologies

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.

ORCParquet
Started byHortonworks with Facebook, to speed up Hive (January 2013)Twitter and Cloudera, for any Hadoop engine (March 2013)
Unit of workStripes; 64 MB by default in the Java writerRow groups; the docs suggest 512 MB to 1 GB
Built-in skippingCount, nulls, min, max (and sum for numbers) per file, stripe and 10,000 rows; optional bloom filtersMin and max per column chunk; optional page index and bloom filters
Nested dataA child column per struct field, list element and map key and value; also a union typeRepetition and definition levels from Google’s Dremel paper
Footer encodingProtocol BuffersThrift
Row updatesHive’s full ACID tables (base and delta files); Hive implements them only for ORCNone in the format; use a table format such as Iceberg or Delta Lake
Table formatsSupported by Iceberg; not by Delta LakeIceberg’s default; Delta Lake’s only data file format
Default for new tables inHive connectors of Trino and PrestoSpark SQL
  • From each project’s own docs and specs, checked 2026-10-06. Spark’s default comes from spark.sql.sources.default; Trino’s from hive.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

  1. 2013

    HIVE-3874 opened in January; ORC ships in Hive 0.11 in May

  2. 2014

    Facebook reports tens of PB moved to ORC; Hive 0.14 adds ACID on ORC

  3. 2015

    Becomes a top-level Apache project in April

  4. 2016

    ORC 1.0 released as a standalone library (January)

  5. 2024

    ORC 2.0.0 released (March)

  6. 2026

    ORC 2.3.1, the current release (July)

Sources28 · facts checked 6 October 2026

Improve this page on GitHub