ecs-typescript
Auto-generated TypeScript type definitions for the Elastic Common Schema (ECS), keeping structured logs, traces, and metrics consistently typed.
Repository Health
Technical Analysis
@elastic/ecs provides TypeScript interfaces for every field group in the Elastic Common Schema (ECS) — the open specification Elastic maintains for normalizing log, metric, and trace event data across sources. Rather than hand-writing types for agent, cloud, container, http, process, and dozens of other ECS field sets, teams import the generated interfaces directly and get compile-time guarantees that the events they emit or ingest actually conform to the schema.
The package itself is a thin, purpose-built code generator wrapped around a large, mechanically produced type library. A CLI (generate-ecs-types) fetches the canonical ecs_nested.yml spec from the elastic/ecs repository at a given ref, walks its field-group structure, and emits one TypeScript file per top-level group plus a combined index — this is how Elastic keeps the published types in lockstep with each ECS release rather than maintaining them by hand.
Because the generation step runs in CI against the upstream schema, the shipped interfaces track ECS version releases closely, giving consumers a low-maintenance way to keep structured-logging and observability payloads schema-correct as ECS evolves.
What You Get
- TypeScript interfaces for every ECS field group (agent, cloud, container, http, process, user, and dozens more), matching the official field names exactly
- A CLI (
generate-ecs-types) that regenerates the type files from anyelastic/ecsref, so consumers or forks can pin to a specific ECS version - Both CommonJS and ESM build outputs (
build/commonjs,build/esm) published from the same generated source, covering either module system without extra config - A combined index export re-exporting every generated interface, so a single import gives access to the full ECS type surface
- Version alignment with upstream ECS releases (9.4.0 tracks ECS 9.4.0), so the types package version signals schema compatibility directly
Common Use Cases
- Typing structured log objects before sending them to Elasticsearch or Logstash, catching field-name typos and shape mismatches at compile time instead of at ingest
- Building internal logging or telemetry wrappers that need to guarantee ECS-conformant output across a codebase with many call sites
- Validating that custom instrumentation or APM-adjacent event payloads match the ECS field groups Elastic’s tooling expects
- Generating a project’s own pinned type snapshot for an older or newer ECS version via the CLI, when the published package version doesn’t match the schema version a team has standardized on
Under The Hood
Architecture
The codebase separates schema acquisition from type synthesis: load_yaml.ts fetches ecs_nested.yml/ecs_flat.yml from the elastic/ecs GitHub repo for a given ref, build_types/build_types.ts walks the resulting nested spec (via buildSpecJson/buildInterfaceProps) into an intermediate JSON tree keyed by internal sentinel markers (__spec, __description, __top_level, __root), and build_types/interface.ts turns that tree into EcsInterface instances that know how to render themselves as TypeScript source. output_definitions.ts, output_schemas.ts, and output_index.ts then handle writing the generated files and index to disk. This pipeline runs once in CI (generate-ecs-types) to produce the checked-in generated/ directory, which is what actually gets compiled into the published package — the CLI itself is a build-time tool, not part of the consumer-facing API.
Tech Stack
A small, TypeScript-first stack: commander drives the CLI surface, js-yaml parses the fetched ECS spec, axios performs the GitHub raw-content fetch, and lodash supplies has/set for the nested-object manipulation in the type-building step. Two separate tsconfig files (tsconfig.commonjs.json, tsconfig.esm.json) compile only the generated/ directory into build/commonjs and build/esm respectively, which is what package.json’s main/module fields point to — the generator source in src/ is excluded from those builds. yarn is the package manager and build orchestrator.
Code Quality
The generator logic has real unit test coverage — build_types/build_types.test.ts, build_types/interface.test.ts, build_types/convert_type.test.ts, build_types/helpers.test.ts, output_index.test.ts, output_definitions.test.ts, output_schema.test.ts, generate_index.test.ts, and interface_to_definition_filename.test.ts all exercise the transformation pipeline with constructed fixtures rather than only the generated output. TypeScript strict mode is enabled project-wide, ESLint with the TypeScript plugin runs in CI (yarn lint), and CI additionally runs test:unit (Jest), a full generate-ecs-types + build, and test:integration (a type-check pass over generated output) on every push and PR — a notably thorough pipeline for a types-generation package.
What Makes It Unique
Most ECS-adjacent tooling in other ecosystems ships hand-maintained or loosely-generated field lists; this package instead treats the ECS YAML spec as the single source of truth and regenerates its entire published surface from it on every release, including a dedicated GitHub Actions workflow (generate.yml) that can be triggered by an upstream ecs-release repository-dispatch event to cut a new types release automatically when ECS itself ships. That keeps the type definitions mechanically synchronized with the schema rather than drifting out of date, which is the main failure mode for hand-written equivalents.