pkvartsianyi/spatio
pkvartsianyi/spatio has 54 GitHub stars and 5 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-15 05:53 UTC. Last push 2026-11-04.
What you can do
- Spatial Queries: Radius search, 2D/3D Bounding box, K-Nearest Neighbors (KNN), Cylindrical queries.
- Object-Centric API: Query around moving objects directly without manual coordinate lookups.
- Trajectories: Optimized storage and querying of historical movement paths over time.
- Durable Persistence: CRC-checked append-only trajectory log with configurable sync policy and checkpoint recovery.
Measured star growth
- in 24h
- 0
- in 7 days
- Collecting history
- in 15 days
- Collecting history
- in 1 month
- Collecting history
Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.
About
An embedded spatial database designed for applications that need to store and query location-based data efficiently.
DataREADME.md
OriginalSpatio
Spatio is a high-performance, embedded spatio-temporal database written in Rust. It's designed for real-time tracking of moving objects, with hot/cold state separation, durable persistence, and native Python, TypeScript and Go bindings.
Quick Start
Python
pip install spatio
import spatio
# Open or create a database
db = spatio.Spatio.memory()
# Upsert an object's location (longitude, latitude)
nyc = spatio.Point(-74.0060, 40.7128)
db.upsert("cities", "nyc", nyc, {"population": 8000000})
# Find objects nearby
nearby = db.query_radius("cities", nyc, 100000, limit=10)
# Returns: [(object_id, point, metadata, distance), ...]
TypeScript
npm install spatio-db
import { Point, Spatio } from 'spatio-db'
// Open or create a database
const db = Spatio.memory()
// Upsert an object's location (longitude, latitude)
const nyc = new Point(-74.006, 40.7128)
db.upsert('cities', 'nyc', nyc, { population: 8000000 })
// Find objects nearby
const nearby = db.queryRadius('cities', nyc, 100000, 10)
// Returns: [{ objectId, point, metadata, distance }, ...]
Rust
[dependencies]
spatio = "0.4"
serde_json = "1"
use spatio::{prelude::*, Point3d};
fn main() -> Result<()> {
let db = Spatio::memory()?;
let nyc = Point3d::new(-74.0060, 40.7128, 0.0);
db.upsert("cities", "nyc", nyc.clone(), serde_json::json!({}), None)?;
let nearby = db.query_radius("cities", &nyc, 100_000.0, 10)?;
println!("Found {} cities", nearby.len());
Ok(())
}
Architecture: Hot/Cold State
Spatio follows a specialized architecture for tracking moving objects:
- Hot State: Current locations are kept in-memory using a sharded concurrent
DashMapand a high-performance R*-tree spatial index. - Cold State: Historical movement (trajectories) is persisted to an append-only log on disk.
:memory:databases have no log: they keep the lastbuffer_capacityupdates per object (default 100), anddeleteremoves them. - Recovery: At startup, the Hot State is automatically rebuilt by scanning the latest entries in the Trajectory Log.
Features
- Spatial Queries: Radius search, 2D/3D Bounding box, K-Nearest Neighbors (KNN), Cylindrical queries.
- Object-Centric API: Query around moving objects directly without manual coordinate lookups.
- Trajectories: Optimized storage and querying of historical movement paths over time.
- Durable Persistence: CRC-checked append-only trajectory log with configurable sync policy and checkpoint recovery.
- Lightweight: No external services, no SQL overhead, and a zero-setup embedded engine.
- Cross-language: Native high-performance Python bindings via PyO3, and Node.js/TypeScript bindings via napi-rs.
- Server Mode: Includes an optional lightweight TCP server for remote access.
Use Cases
Spatio fits applications that track things that move and ask where they are now and where they have been:
- Delivery and logistics fleet tracking
- Drones and airspace monitoring, using 3D and altitude-band queries
- Geofencing with polygon queries
- Nearby search around a moving object
How Spatio Compares
| Spatio | PostGIS | SpatiaLite | Redis GEO | Tile38 | |
|---|---|---|---|---|---|
| Deployment | In-process library, optional server | Server | In-process library | Server | Server |
| Query language | Native API | SQL | SQL | Commands | Commands |
| Movement history | Built in | Model it yourself | Model it yourself | Model it yourself | Model it yourself |
| Stored geometry | Points with metadata | Full geometry | Full geometry | Points | Full geometry |
Choose PostGIS or SpatiaLite for general GIS work, such as joins, arbitrary geometries and hundreds of spatial functions.
Configuration
Spatio exposes a Config builder for tuning performance and persistence.
use spatio::config::{Config, PersistenceConfig};
let config = Config::default()
// Updates kept in memory per object: a read cache for file databases,
// and the entire history of a `:memory:` database
.with_buffer_capacity(100)
.with_persistence(PersistenceConfig {
// Records buffered before the log is flushed to the OS
buffer_size: 512,
});
let db = Spatio::open_with_config("path/to/db", config)?;
with_max_buffered_objects caps how many objects keep that history in memory (default 100,000). The log is unaffected.
db.flush() makes every acknowledged write durable. db.compact(keep_since) shrinks the log by dropping older history, keeping the latest update of each live object. Writes wait while it runs, and it needs free disk space for a second copy of what it keeps, so run it before the disk is full.
Timestamps are seconds since the epoch. Writes stamped more than an hour ahead of the clock are rejected. An update older than an object's current one is added to its history without moving it.
Examples
Tracking Moving Objects
// Update location (upsert)
db.upsert("delivery", "truck_001", position, metadata, None)?;
// Find trucks near a warehouse (coordinate-based)
let nearby = db.query_radius("delivery", &warehouse_pos, 5000.0, 10)?;
// Find drones near a specific drone (object-based)
let near_neighbors = db.query_near("drones", "drone_alpha", 500.0, 5)?;
3D Spatial
// Track drones with altitude
let drone_pos = Point3d::new(-74.006, 40.712, 100.0);
db.upsert("drones", "drone_1", drone_pos, json!({}), None)?;
// 3D Bounding box query
let in_airspace = db.query_within_bbox_3d("drones", min_x, min_y, min_z, max_x, max_y, max_z, 100)?;
Historical Trajectories
// Query movement history for a specific vehicle
let start = SystemTime::now() - Duration::from_secs(3600);
let history = db.query_trajectory("logistics", "truck_001", start, SystemTime::now(), 500)?;
API Overview
Real-time Tracking
upsert(namespace, object_id, position, metadata, options)get(namespace, object_id)delete(namespace, object_id)
Spatial Queries
query_radius(namespace, center, radius, limit)query_bbox(namespace, min_x, min_y, max_x, max_y, limit)query_within_cylinder(namespace, center, min_z, max_z, radius, limit)query_within_bbox_3d(namespace, min_x, min_y, min_z, max_x, max_y, max_z, limit)knn(namespace, center, k)
Object-Relative Queries
query_near(namespace, object_id, radius, limit)query_bbox_near_object(namespace, object_id, width, height, limit)query_cylinder_near_object(namespace, object_id, min_z, max_z, radius, limit)query_bbox_3d_near_object(namespace, object_id, width, height, depth, limit)knn_near_object(namespace, object_id, k)
Server Mode
Spatio includes a dedicated server crate (spatio-server) for multi-process or remote access.
# Start the server
cargo run -p spatio-server
Connect using the native Rust client (spatio-client):
use spatio_client::SpatioClient;
let client = SpatioClient::connect("127.0.0.1:3000".parse()?).await?;
let stats = client.stats().await?;
Documentation
- Architecture: docs/ARCHITECTURE.md
- Operation complexity: docs/COMPLEXITY.md
- Python docs: bindings/python/README.md
- TypeScript docs: bindings/typescript/README.md
- Server docs: crates/server/README.md
- Client docs: crates/client/README.md
- API docs: docs.rs/spatio
License
MIT - see LICENSE