" MicromOne: Building Lightweight Internal Applications with Object Storage Instead of a Database

Pagine

Building Lightweight Internal Applications with Object Storage Instead of a Database

 One of the most common misconceptions in software development is the assumption that every application requires a database.

In reality, many internal business solutions do not manage millions of records, complex relationships, transactional workloads, or analytical queries. They typically collect information from users, store it, retrieve it, and occasionally allow searches or updates.

Examples include:

  • Event registrations
  • Internal campaigns
  • Employee check-ins
  • Training enrollments
  • Surveys
  • Feedback platforms
  • Department initiatives
  • Innovation challenges

For these scenarios, a simpler architecture may provide significant advantages in terms of cost, deployment speed, maintainability, and portability.

The solution described in this article was designed around a core principle:

Use object storage as the persistence layer and store business entities as structured JSON documents.

This approach eliminates the need for a traditional database while preserving the ability to manage records, files, searches, and updates.

The Core Idea

The entire architecture revolves around three components:

Static Frontend
Serverless API
Object Storage

The frontend provides the user experience.

The API provides validation and business logic.

The storage layer provides persistence.

The key design decision is that storage becomes the system's database.

Why JSON Instead of SQL

A traditional database introduces several additional components:

Database Server
Database Configuration
Database Security
Schema Management
Backups
Migrations
Maintenance

For small and medium internal applications, these components often represent more complexity than actual business value.

Instead of storing records inside tables, records can be stored inside a structured JSON document.

Example:

{
  "id": "CHK-001",
  "name": "John Doe",
  "email": "john@example.com",
  "location": "Milan",
  "createdAt": "2026-10-19T10:00:00Z"
}

A collection of registrations becomes:

[
  {
    "id": "CHK-001"
  },
  {
    "id": "CHK-002"
  }
]

Conceptually, the JSON file becomes the application's database.

Using Object Storage as the Database

Instead of creating tables, a storage container is used.

Example:

storage
│
├── checkins.json
└── photos/
``

The file:

checkins.json

contains all structured records.

The folder:

photos/

contains uploaded images.

The application therefore manages only two types of information:

Structured Data
Files

This greatly simplifies the architecture.

Creating a New Record

When a user submits a registration form, the process is intentionally straightforward.

The API performs four operations:

Step 1

Read the current JSON file.

Step 2

Deserialize the JSON structure into memory.

Step 3

Append a new record.

Example:

{
  "id": "CHK-005",
  "name": "Jane Smith"
}

Step 4

Serialize the updated collection and overwrite the JSON file.

The workflow becomes:

Read JSON
Modify Data
Write JSON

This is effectively the same logical process performed by many database systems but implemented using a single structured file.

Updating Existing Records

Updating follows the same principle.

The API:

  1. Loads the current JSON.
  2. Locates the target record.
  3. Updates the fields.
  4. Saves the file again.

Example:

Before:

{
  "status": "Pending"
}

After:

{
  "status": "Approved"
}

No database transactions are required for small workloads.

Reading and Searching Information

When users perform a search:

Search by Name
Search by Email
Search by Location

the API loads the JSON content and applies filters.

Example:

record["name"].contains(searchTerm)

Matching records are then returned to the frontend.

For moderate datasets, this approach remains highly efficient and significantly simpler than maintaining a database server.

Managing Uploaded Images

Images are intentionally kept separate from business records.

A photo uploaded by the user is saved as an independent object.

Example:

photos/
 ├── 8742.jpg
 ├── 8743.jpg
 └── 8744.jpg

The JSON record stores only the reference.

{
  "photoUrl": "photos/8742.jpg"
}

This provides several benefits:

  • smaller JSON files;
  • faster loading;
  • simpler backup strategy;
  • independent file lifecycle management.

Why an API Is Still Necessary

A common question is:

"Why not let the frontend modify the JSON directly?"

The answer is control.

The API performs:

Validation
Authorization
Business Rules
Error Handling
Concurrency Management

Without an API, every client would need direct write access to storage, introducing significant security and data consistency risks.

The API becomes the only component allowed to modify persistent information.

Benefits of This Approach

The architecture offers several practical advantages.

Low Cost

Only storage and API execution are required.

Rapid Development

Applications can be delivered in days rather than weeks.

Minimal Maintenance

There are no database servers to administer.

Easy Backup

The entire dataset can be backed up simply by copying:

checkins.json
photos/

Easy Migration

Moving platforms becomes straightforward because all information already exists in portable formats.


Portability and Self-Hosting

One of the strongest aspects of this architecture is that it remains platform-independent.

The same logical design can run:

In the Cloud

Storage Account
Function App
Static Website

On a Home Server

Nginx
Python API
JSON File
Photos Folder

On a Virtual Machine

Apache
Node.js API
Local Storage

Because the application relies on standard concepts rather than platform-specific services, migration becomes relatively simple.

The storage provider may change, but the application logic remains identical.

When This Architecture Makes Sense

This model is particularly effective when:

  • the number of records is limited;
  • the application is internal;
  • development speed is important;
  • operational costs should remain low;
  • relational data structures are unnecessary.

Typical examples include:

Registration Systems
Check-In Platforms
Training Portals
Employee Surveys
Internal Campaigns
Event Management Applications

The most important architectural decision in this solution was recognizing that a database was not a business requirement.

The real requirement was persistence.

By using object storage to manage:

checkins.json
photos/

and delegating all operations to a lightweight API layer, it was possible to build a solution that remains simple, maintainable, portable, and inexpensive.

Rather than starting with infrastructure, the design starts with the data itself and asks a fundamental question:

"What is the simplest reliable mechanism capable of storing, retrieving, updating, and protecting this information?"

For a large category of internal applications, the answer is often not a database, but a well-structured storage architecture built around JSON documents and object repositories.