DBF to JSONdBase (DBF)
Legacy database files.
dBase, FoxPro, and Clipper database tables. TabularJS reads the field definitions and the records, and returns the field types, lengths and header details alongside the rows.
A .dbf file is a database table: a header, one 32-byte descriptor per field (name, type, length, decimals), then fixed-length records. It is the table format of dBase, FoxPro and Clipper, and it is still common in GIS work, because the attribute table of every ESRI shapefile is a .dbf file.
TabularJS reads the header and the records straight from the bytes and returns a worksheet with one column per field and one row per record. A DBF file has no formulas or styles, so the result is the data plus metadata about the table.
Feature support
What TabularJS extracts from DBF files
- Columns from the field definitions:
titleandnamehold the field name,typeisnumeric,text,checkboxorcalendar, numeric fields with decimals get amask, and date fields getoptions.format. - Values by field type: Character as trimmed strings, Numeric and Float as numbers, Logical as true/false, Date as
YYYY-MM-DDstrings, Integer, Double, Currency and Autoincrement as numbers, DateTime as ISO strings. Empty fields arenull. - Deleted records (flagged with
*) are skipped. Their count is inmeta.deletedRecordsand their positions inmeta.deletedRecordIndices. - Header details in
meta:dbfVersion,lastModified,totalRecords,activeRecords,languageDriverand afieldsarray with the original type letter, length and decimals. - Text fields decoded with the codepage named by the file's language driver byte (for example Windows-1252, Windows-1251 or Shift_JIS), or with the
encodingoption.
Convert DBF to JSON in Node.js
import tabularjs from 'tabularjs';
const result = await tabularjs('products.dbf');
const table = result.worksheets[0];
// One object per record, keyed by field name
const records = table.data.map((row) =>
Object.fromEntries(table.columns.map((col, i) => [col.name, row[i]]))
);
console.log(records[0]);
// { ID: 1, NAME: 'Café crème', PRICE: 3.5, ACTIVE: true, CREATED: '2026-01-15' }
console.log(table.meta.fields[2]);
// { name: 'PRICE', type: 'N', typeName: 'Numeric', length: 8, decimals: 2, jsType: 'numeric' }Read DBF files in the browser
import tabularjs from 'tabularjs';
const input = document.querySelector('input[type=file]');
input.addEventListener('change', async () => {
// Override the codepage when the header does not declare it
const result = await tabularjs(input.files[0], { encoding: 'windows-1251' });
console.log(result.worksheets[0].data);
});JSON output
{
"worksheets": [
{
"worksheetName": "DBF Data",
"data": [
[1, "Café crème", 3.5, true, "2026-01-15"],
[2, "Croissant", 1.2, false, "2026-01-16"]
],
"columns": [
{ "title": "ID", "name": "ID", "width": 100, "type": "numeric" },
{ "title": "NAME", "name": "NAME", "width": 200, "type": "text" },
{ "title": "PRICE", "name": "PRICE", "width": 100, "type": "numeric", "decimal": "..", "mask": "#,##0.00" },
{ "title": "ACTIVE", "name": "ACTIVE", "width": 100, "type": "checkbox" },
{ "title": "CREATED", "name": "CREATED", "width": 100, "type": "calendar", "options": { "format": "YYYY-MM-DD" } }
],
"meta": {
"dbfVersion": "dBASE III",
"totalRecords": 3,
"activeRecords": 2,
"deletedRecords": 1,
"languageDriver": 87,
"fields": [{ "name": "ID", "type": "N", "typeName": "Numeric", "length": 5, "decimals": 0, "jsType": "numeric" }],
"deletedRecordIndices": [2]
}
}
]
}Output for a three-record dBase III table with one deleted record. meta is trimmed: it also has dbfVersionCode, lastModified, recordLength, headerLength, flags and one fields entry per field.
Options
| Option | Effect for DBF |
|---|---|
| encoding | Encoding of the text fields. Default: the codepage of the language driver byte, or Latin-1 when the byte is 0. An unknown name throws Unknown encoding '...'. |
Limitations
- Memo fields (type M) return the block number stored in the .dbf, not the memo text: the .dbt and .fpt memo files are not read.
- General and Picture fields (types G and P) return a placeholder such as
<binary:10bytes>. - DOS codepages (cp437, cp850, cp852...) need iconv-lite, which is used in Node.js only. In the browser those text fields fall back to Latin-1 unless you pass an
encodingthat TextDecoder supports. - Index files (.mdx, .cdx, .ndx) are ignored, and the worksheet is always named
DBF Data.
Frequently asked questions
How do I convert a DBF file to JSON objects?
Use the column names from the field definitions: table.data.map(row => Object.fromEntries(table.columns.map((c, i) => [c.name, row[i]]))). The first row of data is already a record, not a header.
Can I read the attribute table of a shapefile?
Yes. Pass the .dbf file of the shapefile to tabularjs(). You get the attribute rows; the geometry in the .shp file is not read.
Why does a memo field show a number instead of text?
The .dbf file only stores a pointer into a separate memo file (.dbt or .fpt). TabularJS returns that pointer and does not read memo files.
How do I fix garbled characters in text fields?
Pass the codepage the table was written in, for example { encoding: 'cp866' } for Russian DOS files or { encoding: 'windows-1250' } for Central European ones. Without the option, TabularJS uses the codepage declared in the file header.
Are deleted records included?
No. Records marked as deleted are skipped. meta.deletedRecords tells you how many there were and meta.deletedRecordIndices where they were.
Why TabularJS for dBase (DBF)?
- No external spreadsheet parser dependencies: faster installs, smaller bundles.
- One API in Node.js and modern browsers.
- Output is shape-compatible withJspreadsheet: render parsed data in a live workbook with one call.