Turn Redis (indexes) + S3 (storage) into a queryable, transactional document store. 85% cost savings. Zero database complexity.
// Simple API - struct tags = instant queries
import "github.com/adrianmcphee/smarterbase/simple"
type User struct {
ID string `json:"id" sb:"id"`
Email string `json:"email" sb:"index,unique"`
Role string `json:"role" sb:"index"`
Name string `json:"name"`
}
// Zero config - auto-detects from env
db := simple.MustConnect()
defer db.Close()
users := simple.NewCollection[User](db)
// Create with auto-ID
user, _ := users.Create(ctx, &User{
Email: "alice@example.com",
Name: "Alice",
Role: "admin",
})
// Query by any indexed field - O(1)
admins, _ := users.Find(ctx, "role", "admin")
alice, _ := users.FindOne(ctx, "email", "alice@example.com")
99.999999999% data durability via S3 multi-AZ replication
Automatic index repair and circuit breaker protection built-in
S3 handles durability automatically, no backup strategies needed
JSON documents with built-in versioning, migrations happen on read
Append-only event logs, perfect for audit trails and activity logs
Everything you need for document storage, built on infrastructure you already have
// Secondary indexes via Redis Sets
redisIndexer.RegisterMultiValueIndex(
"orders", "user_id",
func(data []byte) (string, string, error) {
var order Order
json.Unmarshal(data, &order)
return order.ID, order.UserID, nil
},
)
// Query - O(1) lookup
orderIDs, _ := redisIndexer.QueryMultiValueIndex(
ctx, "orders", "user_id", "user-123",
)
Multi-value indexes stored in Redis Sets. Query by any field with constant-time lookups.
Redis distributed locks eliminate S3 race conditions. True atomic operations across multiple servers.
// Atomic updates with distributed lock
lock := smarterbase.NewDistributedLock(
redisClient, "smarterbase",
)
smarterbase.WithAtomicUpdate(
ctx, store, lock,
"accounts/123", 10*time.Second,
func(ctx context.Context) error {
var account Account
store.GetJSON(ctx, "accounts/123", &account)
account.Balance += 100
store.PutJSON(ctx, "accounts/123", &account)
return nil
},
)
// Full observability built-in
metrics := smarterbase.NewPrometheusMetrics(
prometheus.DefaultRegisterer,
)
logger, _ := smarterbase.NewProductionZapLogger()
store := smarterbase.NewStoreWithObservability(
backend, logger, metrics,
)
// Automatic tracking:
// - Operation latency (histogram)
// - Success/error rates
// - Circuit breaker state
// - Index health & drift
// - Transaction rollback failures
// - Query performance
Prometheus metrics and structured logging out of the box. Know exactly what's happening in production.
Add a version field, register migrations, and your data transforms automatically on read. No ALTER TABLE statements, no downtime.
// Define version evolution
type UserV0 struct {
Name string
Email string
}
type UserV2 struct {
V int `json:"_v"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string
}
// Type-safe migration function
func migrateUser(old UserV0) (UserV2, error) {
parts := strings.Fields(old.Name)
return UserV2{
V: 2,
FirstName: parts[0],
LastName: strings.Join(parts[1:], " "),
Email: old.Email,
}, nil
}
// Register with zero boilerplate
smarterbase.WithTypeSafe(
smarterbase.Migrate("UserV2").From(0).To(2),
migrateUser,
)
// Old data migrates automatically
var user UserV2
user.V = 2
store.GetJSON(ctx, "users/123", &user)
If you don't need JOINs or complex aggregations, you probably don't need a database
Store user profiles, preferences, sessions. No schema migrations when adding new fields.
Orders, invoices, product catalogs. Index by user, status, date without complex queries.
App configs, feature flags, tenant settings. Update instantly without migrations.
Blog posts, articles, documentation. Store rich JSON without rigid schemas.
Audit trails, activity logs. Append-only JSONL format for efficient writes.
Per-tenant configuration and data. Scale without database partitioning complexity.
85% cheaper than managed databases (1TB data, 1M requests/day)
$41 /month
$271 /month
$300 /month
$100 /month
Get started in minutes with Go 1.18+
go get github.com/adrianmcphee/smarterbase
package main
import (
"context"
"github.com/adrianmcphee/smarterbase/simple"
)
type User struct {
ID string `json:"id" sb:"id"`
Email string `json:"email" sb:"index,unique"`
Name string `json:"name"`
}
func main() {
ctx := context.Background()
// Auto-detects backend (DATA_PATH env or ./data)
db := simple.MustConnect()
defer db.Close()
users := simple.NewCollection[User](db)
// Create - ID auto-generated, indexes auto-updated
user, _ := users.Create(ctx, &User{
Email: "alice@example.com",
Name: "Alice",
})
// Query by indexed field
found, _ := users.FindOne(ctx, "email", "alice@example.com")
}
// Simple API: Indexes auto-created from struct tags
// Just add `sb:"index"` and you're done!
// Core API: Manual index registration for fine control
import "github.com/adrianmcphee/smarterbase"
backend := smarterbase.NewFilesystemBackend("./data")
store := smarterbase.NewStore(backend)
// Setup Redis indexer
redisClient := redis.NewClient(smarterbase.RedisOptions())
redisIndexer := smarterbase.NewRedisIndexer(redisClient)
// Register index with custom logic
redisIndexer.RegisterMultiIndex(&smarterbase.MultiIndexSpec{
Name: "users-by-email",
EntityType: "users",
ExtractFunc: smarterbase.ExtractJSONField("email"),
})
// Use IndexManager for coordinated updates
indexManager := smarterbase.NewIndexManager(store).
WithRedisIndexer(redisIndexer)
user := &User{ID: smarterbase.NewID(), Email: "alice@example.com"}
indexManager.Create(ctx, "users/"+user.ID, user)
// Query with type safety
users, _ := smarterbase.QueryIndexTyped[User](
ctx, indexManager, "users", "email", "alice@example.com",
)
Comprehensive guides and technical documentation
Complete user guide with examples, quick start, and best practices.
Architecture, performance characteristics, and detailed specifications.
Development setup, testing guidelines, and contribution workflow.
7 working examples with interactive code and comparisons. User management, e-commerce, event logging, and more.