.well File Format Specification — Version 2.4: Overview
Version: 2.4 Extension: .well Encoding: UTF-8 Base format: JSON MIME type: application/vnd.well+json JSON Schema: https://welldot.org/schema/v2/well.schema.json JSON Schema draft: 2020-12 JSON-LD Context (optional): https://welldot.org/context/v2.jsonld Status: v2.0 ratified — shipped in @welldot/core v0.2.0 · v2.1 shipped in @welldot/core v0.3.0 · v2.3 shipped in @welldot/core v0.4.0 · v2.4 shipped in @welldot/core v0.5.0
See also: format-reference.md · object-schemas.md · interoperability.md · water-quality.md
Overview
The .well v2 specification is split into five documents. This one gives the context: what changed in each revision (v2.4, v2.3, v2.1 and from v1), why the format exists, the design principles the other parts follow, and the known limitations. The other four are:
- format-reference.md — the top-level fields, versioning and deprecation, datetimes, recommended vocabularies,
well_id,location, units, profiles, extensibility, cross-reference rules and precision. - object-schemas.md — every object schema, the
hydrodynamic_eventsledger,aquifer_analysis,history_logs, the operational blocks (pumps, permits, meters, production, operating regime) and a complete example. - water-quality.md — water samples and results, their units, the parameter vocabulary and regulatory profiles.
- interoperability.md — the JSON-LD context, the relationship to GWML2 and JSON Schema validation.
Table of contents
- Changes in v2.4
- Changes in v2.3
- Changes in v2.1
- Changes from v1
- Purpose
- Design Principles
- Known Limitations of v2
Changes in v2.4
v2.4 files write "version": "2.4"; parsers up to @welldot/core 0.4.0 reject them. Beyond that, v2.4 is an additive revision: every valid v2.3 document stays valid when its version is rewritten, and the integer 2 still means "v2.0 to v2.3, revision unknown".
v2.4 additions:
- version is the string "M.m" (^\d+\.\d+$), compared as two integers,
never as text; patch levels are not allowed; readers accept 1, 2 and
"M.m"
- location.properties.timezone (optional, IANA name): the local date of
an instant is its date converted to this zone; a missing timezone in
a file with condition fulfillments emits the warning missing_timezone
- logger_series (hydrodynamic event type): a continuous level series
recorded by an installed sensor, with sensor_depth, interval,
barometric_compensation and aggregation (none, hourly, daily with
depth_min / depth_max); not a controlled test, not a static level
- LevelReading.datetime: the instant of a reading, required in a
logger_series, where elapsed is absent
- Offline packaging: an optional ZIP (.wellz) with the .well file at
the root and attachments at relative paths; relative uri allowed and
sha256 required only inside the package
- Application extensions: x-<vendor>-<name> is RECOMMENDED
(e.g. x-welldot-custom)
v2.4 clarifications:
- A known hydrodynamic event type is validated against its own schema
and no longer falls back to the open x- rule; step counts per type
are SHOULD (a free count is valid), and steps must be valid
PumpingStep entries
- An optional field without a value is omitted, never written as null
(storativity is no longer nullable); v2 integer files that still
carry it are tolerated on read
- Ledgers MAY be edited in place; editing is NOT RECOMMENDED after a
record has been exported, and corrects remains the way to retract a
measurement. Result.validation is editable too
- Repeated records (collective permits, campaign blanks) share the
same id and SHOULD have identical content; consumers MAY merge them
by id. A fulfillment event_id or sample_id resolves only in the file
of the well that produced it
- Unresolved references MUST be preserved when a file is re-exported,
never silently removed
- A duplicated operating_regime.effective_from and an
estimated_volume period_end not after period_start are warnings
- daily_operating_time above 24 is normalized to 24 with a warning
(the stored value stays as written); a negative value is an error
- Attachment.document_type condition_evidence is typically found in
permits[].conditions[].fulfillments
- The attachment lists (id uniqueness, "root is not an aggregate",
where attachments are allowed) name the same set of records
- history_logs updated_at may be earlier than datetime for a pre-dated
entry; neither ordering emits a warning
- well_id: producers SHOULD mark exactly one entry primary: true; "the
first entry is canonical" is only the fallback
Deprecations
None.
Changes in v2.3
v2.3 is an additive minor revision. Every valid v2.1 document is a valid v2.3 document, and documents keep declaring "version": 2. It adds the operational blocks (equipment, documents, permits, metering, production and operating regime) and the water quality block (water_samples).
v2.3 additions:
- attachments (optional Attachment[]): root-level documents about the
well as a whole (drilling report, as-built drawing, registry record…)
- Attachment becomes a common type and gains document_type
(drilling_report, as_built_drawing, registry_record, photo,
permit_document, condition_evidence, pump_curve, field_sheet,
test_report, lab_report, invoice)
- pump_installations (optional PumpInstallation[]): pump installation
history, with nameplate, intake depth, riser and electrical data
- permits (optional Permit[]): legal instruments governing abstraction
(outorga, dispensa, cadastro) with validity, granted flow, daily
operating time, volume limits, monthly schedule and conditions
(condicionantes) whose deadlines are derived from ISO 8601 date
durations; renewals are linked with supersedes. Each permit carries
its identifier and/or request_identifier (verbatim, any format), a
closed administrative status (requested, granted, suspended,
revoked, denied, withdrawn), an administrative history (filing,
process, notifications, fees, with done/due_date and attachments)
and, on each condition, a responsible and the fulfillments of its
deadlines (datetime, due_date, author, event_id, sample_id,
attachments)
- meters (optional Meter[]): totalizer (hidrômetro) installation
history; device facts only (type, serial, nominal diameter,
max_reading for rollover)
- production (optional ProductionEntry[]): ledger of
meter_reading entries (register values in m³) and estimated_volume
entries (volumes estimated for a period without a meter); volumes
are derived from consecutive readings, never stored as totals.
Volumes declared to a regulator are not production data: they are
the fulfillment of the permit's reporting condition
- operating_regime (optional OperatingRegime[]): declared flow rate,
daily operating time and days per week, each entry in force from
effective_from
- history_logs category status_change, with status (active,
maintenance, inactive, decommissioned, abandoned): the well's
operating status; current status is unknown without one
- history_logs category maintenance gains maintenance_type,
pump_installation_id and meter_id
- history_logs gains hydrodynamic_event_ids and sample_ids (any
category): references to the data an entry produced or observed,
never copies of measured values
- hydrodynamic_events[].corrects: retracts an earlier event (ledger
correction)
- hydrodynamic_events[].attachments, aquifer_analysis[].attachments
- Canonical units kW (power), V (voltage), mm² (cable cross-section),
m³ (volume), h (daily operating time only)
- water_samples (optional WaterSample[]): ledger of water samples,
each with its field and laboratory results in one list
(distinguished by measured_in), sampling point (point depth or
isolated interval, or the production pump), purge and stabilization
readings, laboratory and chain of custody, field QA/QC
(field_duplicate, split_sample via parent_sample_id; blanks),
per-result filtration, lab flags and data validation; corrected
reports and revalidations are new samples with corrects
- Parameter identity { code, vocabulary } with vocabularies welldot,
cas and x-…; the welldot parameter vocabulary (98 codes) is
published as versioned data in @welldot/core, with CAS
equivalences; the unit of a welldot or cas parameter comes from its
code (substances always mg/L), and unit (UCUM) exists only for x-
codes
- Canonical units mg/L, µS/cm at 25 °C, °C, mV, NTU / FNU / FAU / FTU
(by code), Hazen (uH), MPN/100 mL, CFU/100 mL, CFU/mL, Bq/L and µm
- _resolution convention: analyzed_at_resolution and
laboratory.received_at_resolution set to "day" mark an instant
known only by its date; consumers MUST ignore the time of day
- permit condition fulfillments gain sample_id (e.g. a water-quality
monitoring condition)
- well_screen[].slot_type (screen design: continuous_slot, slotted,
bridge_slot, louver, perforated, nold); type remains the screen
material
- Recommended vocabularies for drilling_method, construction materials
(well_case / well_screen / reduction type, riser_material),
well_screen slot_type,
centralizer steels, cement_pad.type, history_logs severity,
measurement_method and aquifer_analysis method; every recommended
vocabulary is published by @welldot/core with en/pt labels
v2.3 clarifications:
- Block kinds: every top-level array is a ledger, a mutable record or
an installation; the kind decides how records are corrected
- Open vocabulary values are stored as their key, never as a
translated label
- Datetime families: legal documents use calendar dates (YYYY-MM-DD),
everything else uses RFC 3339 instants
- Naming rules: no units in field names; nameplate values use the
rated_ prefix; time intervals use period_start / period_end
- supersedes (legal succession between permits) is distinct from
corrects (ledger retraction)
- Permit status and condition deadlines are derived on the local civil
date at the well site, never stored
- Volume derivation is normative: rollover via max_reading, never
across two meters, unknown (never zero or negative) where readings
do not cover; metered volume takes precedence over estimated
volumes
- history_logs category change_of_use is no longer a recommended
value; a change of use is an event entry (the current use lives in
well_purpose)
- Jurisdiction neutrality: water quality limits, exceedances and
national rules are never written to the file; limit sets (WHO, EU,
Brazil…) are data in @welldot/core and local requirements enter
through profiles
v2.3 contains no deprecations.
Changes in v2.1
v2.1 is an additive minor revision. Every valid v2.0 document is a valid v2.1 document, and documents keep declaring "version": 2.
v2.1 additions:
- well_purpose (optional string[]): intended use(s) of the well —
production, monitoring, piezometer, water_level_indicator (INA),
observation, exploration, injection, dewatering
- centralizers (optional Centralizer[]): casing/screen centralizers
as depth interval + spacing
- history_logs category `change_of_use`
v2.1 clarifications:
- well_type describes the construction method only
- Level sign convention: water levels above ground are negative
(made explicit; already implied by "ground level as zero")
Deprecations
| Deprecated | Replacement | Removal |
|---|---|---|
well_type: "artesian" | Construction method in well_type (usually tubular) + negative static_level in hydrodynamic_events | v3 |
Changes from v1
v2.0 additions:
- location object (supersedes top-level lat/lng/elevation)
- well_id (array of authority-scoped identifiers)
- profiles (JSON Schema URLs for regulatory and domain-specific constraints)
- texture object (multi-vocabulary, replaces v1 fgdc_texture string)
- hydrodynamic_events (ledger of water-level observations)
- aquifer_analysis (interpreted aquifer parameter sets)
- history_logs (operational log of interventions and incidents,
with updated_at edit timestamp)
- optional @context (reserved for JSON-LD interoperability)
- optional *_precision fields on key measurements
- WellScreen.screen_slot renamed from screen_slot_mm
v2.0 tightenings:
- All numeric values are SI by spec. The format does not encode a
units declaration; see § Units for the canonical mapping. v1 was
de facto SI in practice and no v1 file in existence declared
non-SI units, so this is a clarification rather than a breaking
change. Display and input units are application concerns.
v2.0 preserves all v1 fields. Parsers must accept v1 documents
unchanged and must accept the following v1-to-v2 normalizations:
- Top-level lat/lng/elevation → location.lat/lng/elevation
- fgdc_texture: "<code>" → texture: { code, vocabulary: "fgdc" }
- screen_slot_mm → screen_slot (value preserved; both versions are
in millimeters)
- bole_hole → bore_hole (v1 typo compatibility)
- diam_pol (inches) → diameter (mm), multiplied by 25.4
Purpose
The .well format is an open standard for representing water well data. It is designed to serve three distinct but complementary use cases:
Visualization. The format contains sufficient constructive and geological detail to produce accurate technical well profile drawings — including borehole geometry, casing strings, screens, gravel packs, lithological columns, fractures, and caves — at true depth scale.
Registration. The format captures the administrative and physical identity of a well, providing a complete static record suitable for submission to regulatory bodies, inclusion in national well registries, and long-term archival.
Research. The structured geological and constructive data, combined with the hydrodynamic event ledger and interpreted aquifer parameters, enables cross-well analysis, aquifer characterization, and hydrogeological research. Field vocabulary choices are aligned with international standards.
Design Principles
- Self-describing — full field names are used throughout; a
.wellfile can be read and understood without consulting the spec. - Versioned — includes a
versionfield for forward compatibility; parsers must reject unrecognized versions. - Self-contained — a single file encodes the complete record of one well.
- Units are SI, declared by spec — all numeric values in a
.wellfile are stored in SI units. The format does not encode a per-file units declaration. See § Units for the canonical unit of each quantity. Conversion to and from a user's preferred display or input units is an application concern. - CRS is declared, not assumed — geographic coordinates are accompanied by an explicit coordinate reference system declaration. The default is WGS84 (
EPSG:4326). - Ground level as zero — all depth values are measured from ground level (0); elevation above the WGS84 ellipsoid (or declared datum) is stored separately in
location.elevation. Water levels above ground are negative. - Geographic north — all azimuth values are referenced to geographic north.
- Three block kinds — every top-level array is one of three kinds, and the kind decides how records are corrected:
- Ledger (
hydrodynamic_events,production,water_samples) — grows by appending. Entries MAY be edited in place, but editing is NOT RECOMMENDED after an entry has been exported. A measurement correction (a re-measurement, a revised laboratory report) is best written as a new entry whosecorrectspoints to the retracted entry; a retracted entry stays in the file but is excluded from every derivation. The format providesid,datetime,sequenceandcorrectsto support this discipline; it does not enforce it. - Mutable record (
history_logs,permits,operating_regime) — edited in place;updated_atrecords the last edit. - Installation (
pump_installations,meters) — equipment present in the well for a period (installed_at/removed_at); edited in place withupdated_at.
- Ledger (
- Derived values are never stored raw —
s/Q,Q/s, drawdowns, and any other value computable from stored fields must not appear as stored fields. Applications compute them on demand. - Jurisdiction neutrality — the file records what was measured, never what it means under a given rule. Water quality limits, exceedances and national requirements are not stored and no field names a national standard; limit sets (WHO, EU, Brazil, …) are versioned data in
@welldot/core, chosen by the consumer at display time, and local obligations (required parameters, sampling frequencies) enter through profiles. - Interpreted results are versioned —
aquifer_analysisrecords which method was used, who performed the analysis, and which events were used as input. Multiple analyses may coexist. - Graceful incompleteness — a record with only a flow rate and a dynamic level is valid. A record with only a static level measurement is valid. Validators must not reject incomplete events.
- Mutable operational log with edit traceability —
history_logsentries are editable to allow correction of field errors. Each entry carries a separateupdated_attimestamp that records when the entry itself was last modified, distinct from thedatetimefield that records when the logged event occurred. - Preserve unknown members — parsers must preserve and pass through any unrecognized fields or top-level blocks without modification, following the GeoJSON foreign members convention. This ensures forward compatibility.
Known Limitations of v2
The following are recognized limitations of this version, reserved for future versions:
- No internationalization of text fields. All free-text fields (
description,notes,author, etc.) are opaque strings with no language tag. A file produced in Brazil will have Portuguese content; one from Norway will have Norwegian. v3 will consider BCP 47 language objects for text fields, with backward-compatible string fallback. - No interpreted water quality assessment.
water_samplesrecords samples and measured results only. Interpreted assessments (water class, hydrochemical facies as a stored judgment, fitness for use) have no block yet; facies, ion balance and exceedances are derived on demand. - Collective permits are repeated per well. A grant covering several wells is repeated in each well's file until cross-file references arrive in v3.
- No geophysical logs block. Downhole geophysical surveys (resistivity, gamma ray, caliper) are out of scope for v2 and reserved for v3.
- No multi-well linking. Storativity determination requires observation well data. The top-level
referencesfield name is reserved for v3 to link wells across files.
.well Format Specification v2.4