Aviation data, open to people and LLMs.
FAA airworthiness directives, NTSB accident investigations, bulletins, data sheets, STCs, advisory circulars, the aircraft registry and more. Download, search and access.
About OpenAirDocs
OpenAirDocs is an independent project to aggregate and organize public aviation data. This data is collected from various APIs and websites of U.S. federal sources.
Our mission is to support a safe and thriving aviation ecosystem.
Our objective with OpenAirDocs is to make aviation data more accessible to human readers, as well as AI models. We publish LLM-friendly data definitions, and our Parquet databases can be queried without download.
More about OpenAirDocsUse the data
Permalinks for all documents
Every document has its own predictable URL at openairdocs.org.
Each document has an AI-friendly Markdown version at the same URL plus .md, to give to an LLM.
Give your model these directions
Paste them into ChatGPT, Claude or another assistant that can run code. It will query the DuckDB file over HTTPS, with no API key, and link the pages it used.
You can query OpenAirDocs, an open copy of U.S. aviation data: FAA airworthiness directives (ADs) with their full text, proposed ADs, SAIBs, type certificate data sheets, STCs, advisory circulars, the aircraft registry with every cancelled registration, service difficulty reports, FAA accident and incident reports, and every NTSB aviation investigation since 1962. Public domain (CC0), release 2026-10-22. QUERY with DuckDB (1.2 or later). Attach the release's one database file over HTTPS; DuckDB reads only the parts each query needs: ATTACH 'https://openairdocs.org/data/latest/openair.duckdb' AS openair (READ_ONLY); USE openair; Tables are then named (FROM faa_directive). Every table and column is described in the file; read a table's descriptions before querying it: SELECT table_name, comment FROM duckdb_tables() WHERE database_name = 'openair'; SELECT column_name, data_type, comment FROM duckdb_columns() WHERE table_name = 'ntsb_case_detail'; Views for common questions: ntsb_pre1982_cause: The causes and factors of NTSB cases before 1982, in words: one row per coded cause or factor, decoded the way NTSB's brief prints it (WEATHER - LOW CEILING). ntsb_case: Every NTSB case in one row, with the facts most questions need: local date, place and point, injuries, aircraft, N-numbers, phase of flight, defining event, probable cause (decoded for cases before 1982) and the case's page. aircraft_history: Everything recorded about one N-number, a row each: the aircraft registered now, cancelled registrations, NTSB investigations, FAA accident and incident reports, and service difficulty reports, with a one-line summary and the record's page. geo_location: Every point of the geo_* tables, with its dataset and record id (as text): one place to map everything. event: Every accident and incident once, NTSB's and the FAA's together: each NTSB case, and each FAA incident report no NTSB case covers (ntsb_faa_incident_report links those that are the same event). openair_page: each record table's web page address, with the SQL that builds it. SELECT record, event_date, summary, page_url FROM aircraft_history WHERE n_number = 'N222UM' ORDER BY event_date; Macros: distance_mi(lat1, lon1, lat2, lon2): Statute miles between two points given in WGS 84 degrees, over the Earth's surface (haversine on a sphere; within 0.5% of the true distance). near(lat, lon, radius_mi): The accidents and incidents (the event view) within radius_mi statute miles of a point, nearest first, with a distance_mi column. Joins: - faa_directive.ad_id joins every faa_directive_* table, and the candidate tables faa_aircraft_model_directive and faa_engine_model_directive that match ADs to registry models. - faa_aircraft_registration (and faa_aircraft_deregistration, where N-numbers repeat) point to faa_aircraft_model.code by aircraft_model_code and to faa_engine_model.code by engine_model_code. - A model_key is the model in upper case with only letters, digits and + (PA-28-181 is PA28181); faa_aircraft_model, faa_engine_model and the product tables carry one. - Each NTSB case is one row of ntsb_case_detail, keyed by mKey; every other ntsb_ table joins on case_mkey. ntsb_aircrafts, faa_incident_report and faa_service_difficulty_report carry n_number. - ntsb_faa_incident_report links NTSB cases (case_mkey, aircrafts_position) to the FAA incident reports about the same aircraft and day (report_number). Watch for: - Matches between records (an AD to an aircraft, an NTSB case to a registration) are candidates. Check each AD's applicability (serial numbers, part numbers, configuration) before saying it applies, and cite AD numbers. - NTSB's eventDate is the UTC date from 1982 on, so an evening event shows the next day: use ntsb_case.event_date_local. - Owner and operator names are spelled as each record reports them: compare upper(name). - Only the Federal Register PDF on govinfo.gov is the official text of an AD. CITE every record by its page on OpenAirDocs. Add .md to any page for a Markdown copy to read: Airworthiness directive (AD) https://openairdocs.org/ad/<AD number> Registered aircraft https://openairdocs.org/aircraft/<N-number> Cancelled registration https://openairdocs.org/deregistered/<N-number>-<cancellation date> Aircraft model https://openairdocs.org/model/<maker-model> Type certificate data sheet (TCDS) https://openairdocs.org/tcds/<number> Supplemental type certificate (STC) https://openairdocs.org/stc/<number> Special airworthiness information bulletin (SAIB) https://openairdocs.org/saib/<number> Advisory circular (AC) https://openairdocs.org/ac/<number> Service difficulty report https://openairdocs.org/sdr/<id> FAA accident or incident report https://openairdocs.org/incident/<report number> NTSB investigation https://openairdocs.org/ntsb/<NTSB number> Without SQL, read pages directly: https://openairdocs.org/aircraft/N333UM.md has an aircraft's registration, the ADs that may apply, and its NTSB and FAA reports. Search: https://openairdocs.org/search.md?q=fuel+selector. Everything registered to an owner: https://openairdocs.org/faa-owner/UNIVERSITY%20OF%20NORTH%20DAKOTA.md; to owners in a town: https://openairdocs.org/faa-place/MI/Ann%20Arbor.md. Accidents and incidents near a point: https://openairdocs.org/map.md?lat=42.2808&lon=-83.7430&mi=10. Lists filter by query: https://openairdocs.org/ntsb.md?state=MI&fatal=1. Every table and recipes: https://openairdocs.org/data/dictionary.md. Everything else: https://openairdocs.org/llms.txt.
Query the DuckDB file
Every table is in one DuckDB file, 813 MB. Attach it over HTTPS and DuckDB fetches only the parts a query needs, so there’s nothing to download first. Or download it and work offline.
Install DuckDB (1.2 or later), start it in a terminal, then run a query. Each table is also a Parquet file, for tools that read Parquet.
duckdb
ATTACH 'https://openairdocs.org/data/latest/openair.duckdb' AS openair (READ_ONLY); USE openair; -- ADs that name a model SELECT d.ad_number, d.status, d.subject, d.effective_date FROM faa_directive_product p JOIN faa_directive d USING (ad_id) WHERE p.model_key = 'PA28181' ORDER BY d.effective_date DESC; -- Every table and column is described in the file SELECT column_name, data_type, comment FROM duckdb_columns() WHERE table_name = 'faa_directive';
-- ADs that name a model, straight from the Parquet files SELECT d.ad_number, d.status, d.subject, d.effective_date FROM 'https://openairdocs.org/data/latest/faa_directive_product.parquet' p JOIN 'https://openairdocs.org/data/latest/faa_directive.parquet' d USING (ad_id) WHERE p.model_key = 'PA28181' ORDER BY d.effective_date DESC;
Query SQLite offline
Every table in two files, indexed for lookups and full-text search. Download once and query offline.
The files are compressed with zstd. Unpack them with zstd -d.
curl -O https://openairdocs.org/data/latest/openair.sqlite.zst zstd -d openair.sqlite.zst sqlite3 openair.sqlite " SELECT ad_number, subject, effective_date FROM faa_directive WHERE status = 'Current' ORDER BY effective_date DESC LIMIT 10;"
Load it from Hugging Face
Every table is also on Hugging Face, in the dataset openairdocs/openairdocs. Browse a table in its viewer, or load it with the datasets library or DuckDB.
Each release is a tag there, so code pinned to one keeps getting the same rows.
from datasets import load_dataset
# One table (a subset) at a time
ads = load_dataset("openairdocs/openairdocs", "faa_directive",
split="train")
# Pinned to a release
ads = load_dataset("openairdocs/openairdocs", "faa_directive",
split="train", revision="2026-10-22")SELECT ad_number, subject, effective_date FROM 'hf://datasets/openairdocs/openairdocs/faa_directive.parquet' ORDER BY effective_date DESC LIMIT 10;