For developers
A .well file is a JSON object with a fixed set of top-level blocks. You can read it with any JSON parser and validate it with the published JSON Schema in any language. In TypeScript or JavaScript, @welldot/core gives you types, validation that matches the spec, and the v1 upgrade.
Read and validate in TypeScript
pnpm add @welldot/core
npm install @welldot/core
yarn add @welldot/core
import { readFile } from 'node:fs/promises';
import { parseWell, type Well } from '@welldot/core';
const text = await readFile('PT-01.well', 'utf8');
// Throws a ZodError (with a path for each problem) when the file is invalid.
// A version 1 file is upgraded to v2 on the way in.
const well: Well = parseWell(text);
console.log(well.name, well.bore_hole.length, well.lithology.length);
Parsing and validating covers the error shape, safeParse and legacy files. Serializing and sharing covers writing a file back.
Validate in other languages
The JSON Schema (draft 2020-12) is published at a stable URL:
https://welldot.org/schema/v2/well.schema.json
Any JSON Schema validator can use it, for example ajv in JavaScript, jsonschema in Python or santhosh-tekuri/jsonschema in Go. The schema is generated from the Zod validators of @welldot/core, so the two accept the same documents. A few rules can only be checked in code; see Validating.
What the shape guarantees
- Required fields.
version,well_type(core identity) and the construction and geology arrays (bore_hole,well_case,reduction,well_screen,surface_case,hole_fill,lithology,fractures,caves, possibly empty) are required. Everything else is optional. See the Well object. Note thatparseWelland the generated JSON Schema currently accept a file withoutwell_type; write it anyway. - Fixed units. Every number has one canonical unit set by the spec, never by the file (Units). Convert on display, not in storage.
- Absent means unknown. Optional fields without a value are omitted, never
null(Absent values). - Unknown members survive. Readers must preserve fields and blocks they do not recognize, prefixed with
x-or not (Extensibility). Do not strip them on save. - Open vocabularies. Most string fields recommend values but accept any string. Show unknown values as they are (Recommended vocabularies).
- String ids, local references. Records point to each other by string
idwithin the same file (Cross-reference rules). A dangling reference is a warning, not an error.
parseWell in @welldot/core currently accepts a file without version. The spec says such a file SHOULD be rejected (parser version handling), so always write it.Parts of the spec to read first
| If you are building | Read |
|---|---|
| A reader or viewer | Top-level structure, Versioning, Units |
| An editor | the above, plus Block kinds, Datetime conventions, Duplicate ids |
| A database or registry | Cross-reference rules, well_id, Interoperability |
| A converter from another format | Units, Precision, Changes from v1 |
Building on .well collects the decisions that matter for editors, databases and pipelines.
Draw and analyze
@welldot/renderdraws a profile into an SVG element with D3.@welldot/utilscomputes volumes, drawdown, permit status, production totals and water quality indicators.
import { parseWell } from '@welldot/core';
import { calculateHoleFillVolume, getLatestStaticLevel } from '@welldot/utils';
const well = parseWell(text);
calculateHoleFillVolume('gravel_pack', well); // m³ of gravel pack
getLatestStaticLevel(well); // m below ground, negative if flowing
Test data
The 19 example wells are complete, valid files covering crystalline, karst, sedimentary, flowing, hand-dug and monitoring wells, plus incomplete and inconsistent records. They ship with @welldot/core as @welldot/core/examples/<file> and are served at https://welldot.org/examples/<file>.
Working with an AI assistant
Point your assistant at this site's MCP server to let it search these docs and validate the .well files it writes, or give it /llms.txt.