cd /news/developer-tools/show-hn-webbase-iii-dbase-iii-rebuil… · home topics developer-tools article
[ARTICLE · art-37491] src=github.com ↗ pub= topic=developer-tools verified=true sentiment=↑ positive

Show HN: WebBase-III – dBASE III rebuilt in the browser with its own interpreter

WebBase-III, a browser-based reimplementation of the dBASE III database system, has been released as an open-source project. The tool includes a full W3Script interpreter, BROWSE grid, form engine, indexing, and multi-user support, all built with TypeScript, Node.js, WebSockets, and SQLite. It allows users to run classic dBASE commands and programs directly in a web browser without installation.

read9 min views1 publishedJun 24, 2026
Show HN: WebBase-III – dBASE III rebuilt in the browser with its own interpreter
Image: source

dBASE III is back. In your browser. USE customers like it's 1984.

Remember the dot prompt? Before SQL won, before ORMs, before anyone said "full-stack" — there was dBASE III. You typed USE customers

, then LIST

, and your data was just there. WebBase-III brings that whole world back: the terminal, the language, BROWSE

, @ SAY GET

forms, .prg

programs, indexes, reports — rebuilt from scratch as a modern web app with its own interpreter in TypeScript, backed by Node.js, WebSockets, and SQLite.

Try it in one click — no install:

The Codespace installs dependencies and starts the dev server automatically. Open the forwarded port 5173 and you're at the dot prompt.

The command interface — type W3Script and see results instantly.

LIST

prints all records in active index order. The status bar shows the active database and table.

INDEX ON name TO BYNAME

creates a SQLite index and activates it — subsequent LIST

output is sorted alphabetically. SEEK "Delta NV"

jumps the record pointer to the first match in O(log n).

BROWSE

opens a spreadsheet-style grid. Records are shown in active index order. Tab/Enter to edit a cell, Ctrl+N for a new row, Delete to remove a row, Esc to return to the terminal.

EDIT <name>

opens the built-in .prg

source editor. Programs support the full W3Script language: DO CASE/ENDCASE

, DO WHILE/ENDDO

, IF/ENDIF

, form layouts, and all data commands. Ctrl+S saves, Esc cancels.

@ row,col SAY "label" GET variable

lays out character-cell form fields. READ

renders them as a live form and waits for the user to fill in values and submit.

The permanent left sidebar with category pickers and action buttons.

Wizards open in the main area with a live W3Script preview.

Feature Details
W3Script interpreter
dBASE III command dialect: navigation, filters, variables, loops, conditionals, forms, programs
BROWSE grid
Inline cell editing, keyboard nav, index-ordered display
Form engine
@ ROW,COL SAY … GET character-cell layout with READ
Indexing
INDEX ON , SEEK , FIND — active index controls all record order
DO CASE
Multi-branch conditional, OTHERWISE fallback
Built-in functions
EOF() , BOF() , FOUND() , RECNO() , SUBSTR() , STR() , AT() , CTOD() , DTOC() and more
Program files
Save, edit, and run .prg scripts with DO / EDIT
The Assistant
Permanent left sidebar — open databases/tables, browse, filter, index, search, design reports, run programs without typing
Multi-user
Each WebSocket connection gets its own isolated interpreter session
Persistent storage
better-sqlite3 with WAL mode — databases survive server restart

The sidebar on the left drives everything without typing: open or create databases and tables, browse and filter data, build indexes, search, design and run reports, and run programs. Every click generates a real W3Script command that echoes into the terminal — watch it to learn the language. Wizards (New table, Filter, report designer, …) open in the main area and show a live preview of the command they will run.

npm install
npm run dev        # http://localhost:5173

Production:

npm run serve      # builds, then serves everything on http://localhost:3000

LAN / Tailscale: the server binds to 0.0.0.0

, so http://<tailscale-ip>:3000

works out of the box.

USE DATABASE mydb
CREATE TABLE customers (name CHAR(40), phone CHAR(20), country CHAR(30))
USE customers

APPEND RECORD
REPLACE name WITH "Acme Corp", phone WITH "555-1234", country WITH "BE"
APPEND RECORD
REPLACE name WITH "Zeta Ltd", phone WITH "555-5678", country WITH "NL"

INDEX ON name TO BYNAME
LIST                        * sorted A→Z

SEEK "Zeta Ltd"             * jump to record instantly
BROWSE                      * open editable grid
SET FILTER TO country == "BE"
LIST                        * filtered view
SET FILTER TO               * clear filter

WebBase-III supports unlimited work areas — each independently holding a table, record pointer, filter, and index. Link areas by key field using SET RELATION TO

for relational data access. Cross-area field access uses alias.field

dot notation.

Note:dBASE III supported a maximum of 10 work areas (DOS file handle limit). WebBase-III has no such limit. dBASE III usedalias->field

arrow syntax; WebBase-III uses modernalias.field

dot notation.

Command What it does
SELECT <alias>
Activate (or create) a work area by name
USE <table> [ALIAS <name>]
Open table in active area; optional alias override
SET RELATION TO <expr> INTO <alias>
Link active area to another; auto-seeks on every navigation
SET RELATION TO
Clear relation on active area
LIST [col, alias.col, ...]
List records; optional column list with cross-area fields
LIST AREAS
Show all open work areas, pointers, indexes, and relations
CLOSE
Close active area's table
CLOSE ALL
Close all work areas, reset to single empty area 1

Cross-area field access: use alias.field

dot notation anywhere an expression is accepted — SET FILTER TO

, IF

, REPLACE

, LIST

, INDEX ON

.

Command What it does
USE <table>
Select a table; restores any saved active index
USE DATABASE <name>
Open a named SQLite database
LIST
Print records in active index order (up to 500)
LIST STRUCTURE
Show column schema
LIST TABLES
Show all tables with record counts
LIST DATABASES
Show all databases on disk (alias: LIST DBS )
BROWSE
Open the editable grid
CLEAR
Clear terminal output
CREATE TABLE <n> (col TYPE, ...)
Create a table
DROP TABLE <name>
Delete a table
APPEND RECORD
Insert a blank row
DELETE / DELETE ALL
Delete current or all records
PACK
VACUUM the SQLite file
GO TOP / GO BOTTOM / GO <n>
Move record pointer
SKIP <n>
Move pointer forward/back
REPLACE <field> WITH <val>, ...
Update field(s) on current row
REPLACE ALL <field> WITH <val>, ...
Update all (filtered) rows
SET FILTER TO <expr>
Set a WHERE clause; empty clears it
Command What it does
INDEX ON <expr> TO <tag>
Create index on expression; sets it active immediately
SET INDEX TO <tag>
Activate a previously created index
SET INDEX TO
Clear active index — restores natural insert order
REINDEX
Rebuild SQLite indexes for current table
LIST INDEXES
Print all indexes for current table with * active marker
SEEK <expr>
Position record pointer at first index match
FIND <string>
Alias for SEEK (unquoted string — dBASE III legacy form)
Command What it does
CREATE REPORT <name>
Create a new report definition (opens JSON editor)
MODIFY REPORT <name>
Edit an existing report definition
REPORT FORM <name>
Run report — ASCII to terminal + HTML preview panel
LIST REPORTS
List all saved report definitions
DELETE REPORT <name>
Delete a report definition
Command What it does
DO <name>
Run a saved .prg program
EDIT <name>
Open .prg source editor
LIST PROGRAMS
Show all saved programs

Demo programs live in

demos/*.prg

and are the single source of truth: they are seeded into the program store on every server start, overwriting any store copy. TryDO inventory

for a full interactive showcase (work areas, relations, indexes, forms).

Command What it does
STORE <val> TO <var>
Assign a variable
INPUT "prompt" TO <var>
Collect keyboard input
@ r,c SAY "text" GET <var>
Define a form field
READ
Display the form and wait for submit
Command What it does
IF <cond> … ENDIF
Conditional block
DO WHILE <cond> … ENDDO
Loop
DO CASE … ENDCASE
Multi-branch conditional (CASE , OTHERWISE )
HELP
Print command reference
QUIT
Exit

Functions work anywhere an expression is accepted — IF

, DO WHILE

, STORE

, REPLACE

, INDEX ON

, SET FILTER TO

, etc.

Function Returns
EOF()
True if record pointer is past last record
BOF()
True if record pointer is before first record
FOUND()
True if last SEEK / FIND matched
RECNO()
Current record number
RECCOUNT()
Total records in current table
UPPER(str)
Uppercase
LOWER(str)
Lowercase
TRIM(str)
Strip leading and trailing spaces
LTRIM(str)
Strip leading spaces only
SUBSTR(str, start, len)
Substring — 1-based; len optional (to end)
LEN(str)
String length
AT(needle, haystack)
1-based position; 0 if not found (case-sensitive)
STR(num, len, dec)
Number to right-justified string; default len=10, dec=0
VAL(str)
String to number; non-numeric → 0
INT(n)
Truncate toward zero
ABS(n)
Absolute value
SPACE(n)
String of n spaces
REPLICATE(str, n)
Repeat string n times
DATE()
Today as MM/DD/YY
DTOC(date)
Date to display string MM/DD/YY
CTOD(str)
Display string MM/DD/YY to ISO date

W3Script supports both styles:

Syntax Value
TRUE / FALSE
Boolean true/false
.T. / .TRUE.
Boolean true (dBASE III style)
.F. / .FALSE.
Boolean false (dBASE III style)

Boolean values display as .T.

/ .F.

in output to match dBASE conventions.

Logical operators are accepted in both styles too: NOT

/ .NOT.

, AND

/ .AND.

, OR

/ .OR.

(e.g. DO WHILE .NOT. EOF()

).

Key Action
Arrow keys Navigate cells
Enter / F2 Edit selected cell
Tab / Shift+Tab Move right / left
Ctrl+N New row
Delete Delete current row
F5 Refresh from DB
Esc Exit grid, return to terminal
server/
  index.ts              Node.js HTTP + WebSocket server (port 3000)
  Session.ts            Per-connection session: parses commands, drives Executor
  SessionManager.ts     Tracks all active sessions
  ServerDatabaseBridge.ts  IDatabaseBridge impl wrapping better-sqlite3
  ProgramStore.ts       .prg program storage in data/system.sqlite3
  IndexStore.ts         Index metadata + active index in data/system.sqlite3

src/
  interpreter/
    Lexer.ts            Tokenises W3Script input (case-insensitive)
    Parser.ts           Recursive-descent AST builder
    Executor.ts         Async AST runner; manages db/table/filter/vars/rowPtr/activeIndex
    Builtins.ts         Stateless built-in function implementations

  terminal/
    Terminal.ts         REPL UI — command history, multi-line block accumulation

  ui/
    Grid.ts             BROWSE spreadsheet — inline cell editing, keyboard nav
    FormLayout.ts       @ SAY GET form engine — character-cell coordinates
    ProgramEditor.ts    .prg source editor UI

  ws/
    WsClient.ts         Browser WebSocket client
npm test                    # unit + integration tests (Vitest)
npx playwright test         # end-to-end browser tests (requires dev server running)

The Playwright suite (tests/integration.spec.ts

, tests/crm.spec.ts

) drives a real browser against the running app and covers navigation, filters, indexing, programs, forms, and BROWSE.

AGPL-3.0 — see LICENSE.md.

Why AGPL? WebBase-III is a toy, and the license keeps it that way: anyone can use it, fork it, and learn from it, but nobody can take it closed and sell it as a hosted service without giving their changes back. If you want to run it, hack it, or ship features from your dBASE memories — that's exactly what it's for.

── more in #developer-tools 4 stories · sorted by recency
── more on @webbase-iii 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-webbase-iii-…] indexed:0 read:9min 2026-06-24 ·