eeCLOUD 4.1.0
dotnet add package eeCLOUD --version 4.1.0
NuGet\Install-Package eeCLOUD -Version 4.1.0
<PackageReference Include="eeCLOUD" Version="4.1.0" />
<PackageVersion Include="eeCLOUD" Version="4.1.0" />
<PackageReference Include="eeCLOUD" />
paket add eeCLOUD --version 4.1.0
#r "nuget: eeCLOUD, 4.1.0"
#:package eeCLOUD@4.1.0
#addin nuget:?package=eeCLOUD&version=4.1.0
#tool nuget:?package=eeCLOUD&version=4.1.0
eeCLOUD
eeCLOUD is a .NET data engine built around a high-performance logical storage model.
It is designed for teams that want:
- a very fast persistence layer
- a schema-flexible model
- automatic database and table bootstrap
- simple APIs for structured and semi-structured data
eeCLOUD is not a traditional ORM.
It does not start from an entity-to-table relational model.
Instead, it works through its own logical concepts such as Application, Memory, MemoryArea, Address, Index, ID, Reference, date and create.
At its core, eeCLOUD is optimized for productivity first, while still keeping a strong focus on real-world performance.
Installation
dotnet add package eeCLOUD
Requirements:
- .NET 8.0 or later
Quick Start
using eeCLOUD;
var config = new Config
{
server = "127.0.0.1:5432",
username = "postgres",
password = "your-password",
type = ServerType.PostgreSQL
};
var db = new Application(config);
await db.WriteData("myapp", "users", "user_001", new
{
email = "hello@example.com",
role = "admin",
enabled = true
});
Memory user = await db.ReadData("myapp", "users", "user_001");
Databases and tables are created automatically when needed.
Core Concepts
Application
An Application is the top logical container.
On SQL backends it typically maps to a database.
Memory
A Memory is the logical equivalent of a table or collection.
It is the main addressable storage space in eeCLOUD.
MemoryArea
A MemoryArea is a single stored record inside a Memory.
Address
- Type:
long - unique
- monotonic
- primary physical identifier
The address is the closest concept to a physical storage address.
Index
- Type:
string - unique logical identifier
- commonly a GUID
Useful for external integration, semantic lookup and stable identifiers.
ID
- Type:
string - not unique
- indexed
Useful for grouping, partitioning and NoSQL-style queries.
Reference
- Type:
long - points to the
addressof another record
Useful when you want fast direct links between memories.
date vs create
date: business or logical datecreate: actual persistence timestamp
date is especially important for range queries and time-based data access.
Storage Paradigms
eeCLOUD currently supports two complementary paradigms.
1. Raw JSON Paradigm
This is the original high-performance eeCLOUD model.
The whole object is stored as JSON in a single MemoryArea.
await db.WriteData("myapp", "users", "user_001", new
{
email = "hello@example.com",
profile = new
{
displayName = "Giovanni",
theme = "dark"
}
});
Best for:
- transaction-heavy flows
- hot paths
- maximum write/read throughput
- simple and compact storage
2. Object Graph Paradigm (V4)
With the new object paradigm, nested objects can be persisted as dedicated child memories.
The parent record stores only GUID references to child objects, and eeCLOUD reconstructs the full graph automatically during read.
public class Account
{
public long id { get; set; }
public string email { get; set; } = "";
public string password { get; set; } = "";
public bool enabled { get; set; } = true;
public bool terms { get; set; }
public ClientConnectionInfo registrationInfo { get; set; } = new();
public DateTime registrationDate { get; set; }
public ClientConnectionInfo connectionInfo { get; set; } = new();
}
Example write:
await db.WriteObjectData("myapp", "accounts", "acc_001", account);
Conceptually, the parent memory stores something like:
{
"id": 1,
"email": "hello@example.com",
"password": "secret",
"enabled": true,
"terms": true,
"registrationInfo": "guid-child-1",
"registrationDate": "2026-04-24T18:00:00Z",
"connectionInfo": "guid-child-2"
}
And the children are saved in dedicated memories such as:
accounts§registrationinfo
accounts§connectioninfo
Best for:
- user profiles
- dashboard-managed settings
- rich configuration objects
- models that evolve over time
- gradual refactors of old projects
Current SQL engine support for the V4 Object Graph fast path:
- PostgreSQL
- MySQL
- SQL Server
Additional notes:
eeCACHEsupports the same Object Graph APIs with its own backend semantics.FTPdoes not support Object Graph persistence.SFTPdoes not support Object Graph persistence.
Raw JSON vs Object Graph
Use WriteData / ReadData when:
- you want the fastest path
- nested objects do not need to be separated
- you prefer a single JSON payload
Use WriteObjectData / ReadObjectData when:
- nested objects should live in dedicated child memories
- you want a more modular storage model
- your object graph grows over time
- readability and maintainability matter more than raw peak throughput
In general:
Raw JSONremains the best fit for high-throughput transactional flowsobject graphis ideal for structured configuration-style data- the optimized SQL Object Graph write path now uses a batched persistence flow, which keeps warm write performance close to the Raw JSON path
Write APIs
Raw JSON write
await db.WriteData("myapp", "orders", "ord_001", new
{
number = "2026-0001",
total = 129.90m
});
Object write
await db.WriteObjectData("myapp", "accounts", "acc_001", account);
There are also overloads with:
- explicit
index - explicit
date referenceclusterized: true
Read APIs
Raw JSON read
Memory data = await db.ReadData("myapp", "orders", "ord_001");
Memory list = await db.ReadAllData("myapp", "orders");
Object read
ObjectMemory<Account> accountData =
await db.ReadObjectData<Account>("myapp", "accounts", "acc_001");
Read by latest record:
ObjectMemory<Account> lastAccount =
await db.ReadObjectData<Account>("myapp", "accounts");
Read by index:
ObjectMemory<Account> indexed =
await db.ReadObjectIndexData<Account>("myapp", "accounts", "some-index");
ReadAllObjectData
ReadAllObjectData<T> returns:
- the raw
Memory - the rebuilt typed list
List<T>
ObjectMemories<Account> allAccounts =
await db.ReadAllObjectData<Account>("myapp", "accounts");
Range query:
ObjectMemories<Account> accountsInRange =
await db.ReadAllObjectData<Account>(
"myapp",
"accounts",
DateTime.UtcNow.AddDays(-7),
DateTime.UtcNow,
Order.ASC);
Field filter:
ObjectMemories<Account> enabledAccounts =
await db.ReadAllObjectData<Account>(
"myapp",
"accounts",
"email",
"hello@example.com");
The ReadAllObjectData<T> overloads mirror the Raw JSON ReadAllData(...) patterns for:
- full reads
referenceidfield/value- date ranges
- paging
Update APIs
Raw JSON update
await db.UpdateData("myapp", "orders", address, new
{
number = "2026-0001",
total = 149.90m
});
Object update
await db.UpdateObjectData("myapp", "accounts", address, account);
Object update semantics:
- current child objects in the new payload are rewritten
- missing child memories are created automatically when needed
- the parent is updated with the new GUID references
- existing Raw JSON rows can be converted in-place to Object Graph rows through
UpdateObjectData(...) - removed children are no longer referenced
- old child rows are not automatically deleted
On PostgreSQL, MySQL and SQL Server, the Object Graph update path now batches child persistence before updating the parent row, so updates no longer degrade into one write round-trip per nested child.
This makes updates safer and predictable, especially in configuration-oriented scenarios.
Mixed Raw JSON/V4 Mode
eeCLOUD supports gradual migration of existing memories.
This means the same memory can contain:
- existing Raw JSON rows with nested inline JSON
- new V4 rows with GUID references to child memories
To enable mixed compatibility during object reads:
ObjectMemory<Account> accountData =
await db.ReadObjectData<Account>(
"myapp",
"accounts",
"acc_001",
mixed: true);
Use mixed: true when:
- you are refactoring old projects
- the memory already contains Raw JSON rows
- you want to migrate gradually instead of renaming tables
Default behavior is mixed: false, which keeps the standard V4 optimized path.
Schema Evolution
The object graph model supports progressive schema evolution.
If a new child object is added in the future:
- old rows remain readable
- missing child objects are returned as
null/ default values - the new child memory is created only when a record actually writes that child
This makes the model practical for long-lived applications that evolve over time.
Cluster Storage
eeCLOUD supports clustered storage to improve scalability on very large memories.
Cluster creation
Clusters are created only during write operations by explicitly enabling:
clusterized: true
Example:
await db.WriteData("myapp", "orders", "ord_001", order, clusterized: true);
await db.WriteObjectData("myapp", "accounts", "acc_001", account, clusterized: true);
When clustering is enabled:
- the logical parent memory remains stable
- data is written to cluster memories such as
orders§c_0 - cluster resolution is calculated automatically from the address
Example:
orders
orders§c_0
orders§c_1
orders§c_2
Automatic cluster resolution on read
Reads do not need any special flag.
eeCLOUD resolves the cluster automatically, so consumers always read using the logical memory name.
For the object graph model:
- the parent memory can be clusterized
- child object memories remain transparent and are handled automatically
eeCACHE
eeCACHE is an optional persistent cache engine for eeCLOUD.
It is disabled by default and must be injected explicitly:
var cache = new eeCACHE();
var db = new Application(config, cache);
Architecture
eeCACHE uses two layers:
in-memory layer
- very fast
- process-local
- supports TTL / expiration
persistent layer
- local memory-mapped storage
- survives process restart
- can be shared across processes on the same machine
Usage modes
As primary backend:
config.type = ServerType.eeCACHE;
As local accelerator in front of a SQL backend:
- SQL remains the source of truth
- eeCACHE speeds up reads and writes locally
Configuration
var config = new Config
{
server = "192.168.1.10:5432",
username = "dbuser",
password = "dbpassword",
type = ServerType.PostgreSQL,
clusterSize = 100000
};
server
- format:
hostorhost:port - if port is omitted, the backend default is used
username / password
Credentials for the selected backend engine.
The user should be allowed to create databases and tables if you want full automatic bootstrap.
clusterSize
Maximum number of records per cluster before eeCLOUD moves to the next cluster.
Supported Backends
- PostgreSQL
- MySQL
- SQL Server
- eeCACHE
- FTP
- SFTP
SFTP on Windows Server
SFTP is a good fit when you want a remote file backend without the operational overhead of a classic FTP/FTPS server.
Typical eeCLOUD config:
var config = new Config
{
server = "your-server:22",
username = "sftp-user",
password = "your-password",
type = ServerType.Sftp
};
Notes:
serversupportshostorhost:port- if the port is omitted,
SFTPfalls back to port22 - the
SftpEngineuses the SFTP root directory exposed to the configured user - on Windows Server this is typically the user's SFTP home or
ChrootDirectory
Windows Server checklist
On Windows Server with OpenSSH Server:
- make sure
sshdis running - enable the inbound firewall rule for the active network profile
- add the SFTP user to the
OpenSSH Usersgroup - optionally force
internal-sftpand set a dedicatedChrootDirectory
Useful commands:
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
Set-NetFirewallRule -Name OpenSSH-Server-In-TCP -Profile Private,Public
Add-LocalGroupMember -Group "OpenSSH Users" -Member "sftp-user"
Restart-Service sshd
Example sshd_config block:
Subsystem sftp sftp-server.exe
AllowGroups administrators "openssh users"
Match User sftp-user
ForceCommand internal-sftp
ChrootDirectory C:\inetpub\wwwroot\CDN
PasswordAuthentication yes
AllowTcpForwarding no
X11Forwarding no
With a configuration like this, eeCLOUD writes under the SFTP root seen by the user, for example:
C:\inetpub\wwwroot\CDN\<app>\<memory>\...
The SftpEngine also maintains a metadata index file for each memory:
<app>/<memory>/.eecloud.index.json
When to Use eeCLOUD
Recommended for:
- IoT backends
- logging and event streams
- session and state storage
- dashboard-driven configuration
- semi-structured data
- high-throughput backend services
Less suitable for:
- complex relational SQL joins as the main workload
- heavy analytical SQL reporting
- classic schema-first ORM-centric architectures
Notes on Performance
eeCLOUD is designed to give you a choice.
- the Raw JSON paradigm remains the reference path for hot transactional workloads
- the Object Graph paradigm introduces more structure and flexibility
- on PostgreSQL, MySQL and SQL Server,
WriteObjectData(...)andUpdateObjectData(...)now use a batched Object Graph persistence flow - without batching, Object Graph writes and updates would scale almost linearly with the number of child and nested child objects because every branch would require separate write round-trips
- in steady-state SQL scenarios,
WriteObjectData(...)can now run very close toWriteData(...)
In practical terms:
- use
WriteData/ReadDatafor maximum raw performance - use
WriteObjectData/ReadObjectData/ReadAllObjectDatawhere a modular graph model gives you more value - prefer Raw JSON when the payload is compact and the hottest path is pure throughput
- prefer Object Graph when maintainability, schema evolution and child-memory separation matter more than a fully monolithic JSON payload
Links
- Website: https://eecloud.io
- API reference: https://eecloud.io/docs
Made with love by Giovanni Petruzzellis
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- FluentFTP (>= 54.1.2)
- MySqlConnector (>= 2.5.0)
- Npgsql (>= 10.0.2)
- SSH.NET (>= 2025.1.0)
- System.Data.SqlClient (>= 4.9.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.1.0 | 86 | 5/10/2026 |
| 4.0.1 | 99 | 5/1/2026 |
| 4.0.0 | 103 | 4/28/2026 |
| 3.3.7 | 107 | 4/9/2026 |
| 3.3.6 | 114 | 3/31/2026 |
| 3.3.5 | 112 | 3/19/2026 |
| 3.3.4 | 105 | 3/6/2026 |
| 3.3.3 | 141 | 2/3/2026 |
| 3.3.2 | 146 | 1/2/2026 |
| 3.2.0 | 205 | 11/23/2025 |
| 3.1.9 | 228 | 10/28/2025 |
| 3.1.8 | 222 | 10/21/2025 |
| 3.1.6 | 213 | 10/20/2025 |
| 3.1.5 | 135 | 10/18/2025 |
| 3.1.4 | 220 | 10/15/2025 |
| 3.1.3 | 220 | 10/13/2025 |
| 3.1.1 | 257 | 9/7/2025 |
| 3.1.0 | 268 | 9/4/2025 |
eeCLOUD 4.1.0 introduces the new SFTP backend and expands file-based engine support for remote binary storage scenarios.
Highlights in this release:
- Added `SftpEngine` as a new backend using password-based OpenSSH / SFTP connections.
- Added `ServerType.Sftp` support across the shared core engine selection flow.
- Added SFTP support for file-based write, read, count, size, update, rename, delete, restore and erase operations.
- Extended file-engine payload handling so SFTP follows the same binary write model used by FTP.
- Added package metadata and README updates for the new SFTP backend.
- Added Windows Server setup notes for OpenSSH, firewall profiles and `OpenSSH Users` membership.
- Preserved the current file-backend positioning where Object Graph persistence is not supported on FTP/SFTP.