Building Z-RevixDB Without Dependencies: What We Had to Rebuild
Z-RevixDB — Data That Remembers
Modern software development makes it easy to build powerful applications. Need an HTTP server? Install a framework. Need database access? Install an ORM. Need search? Install a search engine. Need object comparison? Install a library.
But what happens when you are told:
"Your dependency manifest must be empty"
That was the challenge behind Z-RevixDB, our attempt to build a useful versioned data storage and recovery platform using only the standard library.
The goal wasn't simply to remove packages. The real challenge was understanding what those packages were actually doing for us and rebuilding only the functionality we genuinely needed.
*The Problem We Wanted to Solve
*
Most data systems are primarily concerned with the current state of data.
A record might look like:
{
"name": "John Doe",
"plan": "Basic",
"status": "Active",
"credit_limit": 500000
}
Later, someone changes the plan:
Basic → Pro
and the credit limit:
₹5,00,000 → ₹8,00,000
The current state is easy to see.
But important questions remain:
What changed?
When did it change?
What was the previous state?
Why was it changed?
Can we inspect the old state?
Can we safely recover it?
This led us to build Z-RevixDB — Data That Remembers.
Instead of treating an update as a replacement, Z-RevixDB treats it as a new version.
V1 → V2 → V3 → V4
The history becomes part of the data.
The Zero-Dependency Constraint
For this hackathon, we couldn't simply install our preferred tools.
Normally, a project like this could involve frameworks, database abstraction layers, HTTP libraries, validation libraries, search libraries, and comparison utilities.
Instead, we started asking a different question:
What does this package actually provide, and can we build the required part ourselves using the standard library?
That became one of the most interesting parts of the project.
What We Normally Would Have Used
Our replacement strategy looked roughly like this:
Normally------- ----Z-RevixDB
Flask / FastAPI-------http.server & custom rounting
SQLAlchemy------------sqlite3
Requests--------------urllib / http.client
Pydantic--------------Custom validation
DeepDiff--------------difflib + custom comparison logic
Elasticsearch / Whoosh---Custom inverted index
External hashing library--hashlib
File utilities-------pathlib
UUID package---------uuid
Date/time libraries---datetime
The important part is that we didn't copy third-party source code into the project.
We used the primitives available in the language itself and implemented the application-specific functionality ourselves.
Building the Web Layer
One of the first questions was:
How do we create a web application without Flask or FastAPI?
Python's standard library already provides http.server.
That gave us the foundation for handling HTTP requests.
We then implemented the application-level routing and request handling ourselves.
Conceptually:
Browser
↓
HTTP Server
↓
Request Routing
↓
Application Logic
↓
Storage / Version Engine
This was a good reminder that frameworks don't create HTTP—they provide convenient abstractions around it.
Building Versioned Storage
The heart of Z-RevixDB is the version engine.
Instead of:
Update Record
↓
Overwrite Old Data
we use:
Create Record
↓
Version 1
↓
Modify Record
↓
Version 2
↓
Modify Again
↓
Version 3
Each version can retain information such as:
Record identifier
Version number
Data snapshot
Timestamp
Commit message
Integrity information
SQLite, through Python's sqlite3 module, provides persistent storage without requiring an external database server or ORM.
The Interesting Part: Recovery
One of the design decisions that became particularly important was recovery.
Suppose we have:
V1 → V2 → V3 → V4
and V4 contains an incorrect value.
A tempting implementation would be to replace V4 with V2.
But that would destroy history.
Instead, Z-RevixDB creates a new version:
V1 → V2 → V3 → V4 → V5
↑
Restored fromV2
So recovery doesn't mean:
“Delete the past.”
It means:
“Create a new current state based on the past.”
That preserves the complete lineage.
Building Search Without a Search Library
Search was another interesting challenge.
We wanted users to search versioned structured data without depending on Elasticsearch, Whoosh, or another search package.
So we built an inverted index.
The simplified flow is:
JSON Records
↓
Tokenization
↓
Inverted Index
↓
Prefix Lookup
↓
Field Matching
↓
TF-IDF Ranking
↓
Relevant Results
The search system supports:
Exact token matches
Prefix searches
Field matching
Deep nested JSON keys
Relevance ranking
For example, a user could search for:
Java
and discover a value such as:
JavaScript
through prefix matching.
A nested value such as:
{
"address": {
"city": "New York"
}
}
can also be discovered through nested-field search.
This was a particularly valuable exercise because it showed us how much functionality is normally hidden behind a search library.
Version Comparison
Another requirement was comparing two versions.
Instead of installing a JSON-diff package, we used standard-library functionality such as difflib together with application-specific comparison logic.
The goal is not simply to say:
V1 != V2
but to expose meaningful changes:
plan:
- Basic
- Pro
credit_limit:
- 500000
- 800000 That makes version history useful rather than simply archival.
Integrity Verification
Version history is valuable only if users can trust it.
Z-RevixDB therefore uses hashing to maintain integrity information for stored versions.
Python's hashlib provides the required cryptographic hashing primitives.
The conceptual flow is:
Version Data
↓
Hash
↓
Store Integrity Information
↓
Verify Later
↓
Valid / Potentially Modified
The Integrity Monitor can then scan records and report verification results.
Audit Trail
Version history tells us how data evolved.
The Audit Trail answers a slightly different question:
What happened in the system?
The system records relevant activities and provides an audit view containing information such as:
Audit Events
Unique Actors
Record Mutations
Security Incidents
Users can filter activity by things such as:
Action
User
Target Record ID
Date Range
and inspect events chronologically.
This makes the platform useful not only for recovery but also for accountability.
The Standard Library Was Bigger Than We Expected
One of the biggest surprises during development was realizing how much functionality was already available.
Some of the modules we relied on include:
sqlite3
hashlib
json
http.server
urllib
pathlib
datetime
uuid
threading
difflib
None of these were specifically created for Z-RevixDB.
But together, they provided a surprisingly strong foundation for building a complete application.
The challenge was not finding one magical replacement for every package.
It was learning how to compose smaller primitives into the functionality we needed.
What Was Harder Than the Documentation Made It Look?
The hardest lesson was that replacing a package is rarely a one-to-one substitution.
For example:
Flask → http.server
sounds simple.
But Flask normally provides many conveniences around routing, request handling, responses, error handling, and application structure.
Similarly:
Elasticsearch → custom search
is not simply an import replacement.
You need to think about:
Index construction
Tokenization
Lookup
Prefix matching
Ranking
Field information
Nested data
Result ordering
The package hides complexity.
Removing the package means that complexity becomes your responsibility.
That was the real learning experience.
What Zero Dependency Changed About Our Design
Initially, we thought the constraint would mainly affect installation.
It ended up affecting our architecture.
Every time we wanted to use a library, we had to ask:
What problem does it solve?
Then:
What is the minimum functionality we actually need?
And finally:
Can the standard library provide the primitive required to implement it?
This prevented us from blindly adding technology.
We became much more conscious of what each component of the system was actually doing.
What We Learned
Building Z-RevixDB taught us that dependencies aren't necessarily bad.
They save enormous amounts of engineering time.
But using them can also make it easy to forget what happens underneath.
The Zero Dependency constraint forced us to look underneath those abstractions.
We had to think about:
HTTP → Routing → Storage → Indexing → Hashing → Comparison → Versioning → Recovery
instead of simply installing a package for each problem.
And that was probably the most valuable part of the challenge.
Final Thought
Z-RevixDB started with a simple idea:
Don't just store data. Remember its history.
The Zero Dependency challenge added another question:
How much of that system can we build ourselves using only what our language already provides?
The answer turned out to be much more than we initially expected.
We didn't just remove dependencies.
We discovered what those dependencies were actually doing for us.
Z-RevixDB
DATA THAT REMEMBERS.
Git remembers code. Z-RevixDB remembers data.
Top comments (0)