New in ADR-0006: QueryWithFallback + Boilerplate Reduction Helpers (85% less code!)

Skip the Database. Use Redis + S3 Instead.

Turn Redis (indexes) + S3 (storage) into a queryable, transactional document store. 85% cost savings. Zero database complexity.

Go 1.18+
MIT License
Production Ready
// 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")

Instead of This → Do This

Traditional Database

RDS PostgreSQL: $271/month
❌ ALTER TABLE downtime
❌ Database servers to patch
❌ Backup strategies to test
❌ Connection pools to tune
❌ DBA expertise required

SmarterBase

Redis + S3: $36/month
✅ No ALTER TABLE statements
✅ Zero servers (S3 is serverless)
✅ Zero backups (11 9s durability)
✅ Simple key-value (no tuning)
✅ Junior devs can deploy

Why Developers Choose SmarterBase

11 9s Durability

99.999999999% data durability via S3 multi-AZ replication

Self-Healing

Automatic index repair and circuit breaker protection built-in

Zero Backups

S3 handles durability automatically, no backup strategies needed

Schema Evolution

JSON documents with built-in versioning, migrations happen on read

JSONL Support

Append-only event logs, perfect for audit trails and activity logs

Database Features Without the Database

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",
)
Secondary Indexes

Fast O(1) Lookups via Redis

Multi-value indexes stored in Redis Sets. Query by any field with constant-time lookups.

  • O(1) index queries
  • 1:N relationships (user → orders)
  • Automatic index updates
  • Self-healing with auto-repair
  • Circuit breaker protection
Distributed Locks

Race-Free Updates

Redis distributed locks eliminate S3 race conditions. True atomic operations across multiple servers.

  • Prevents lost updates
  • Automatic retry with backoff
  • TTL protection against deadlocks
  • Production-tested at scale
// 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
Observability

Production-Grade Monitoring

Prometheus metrics and structured logging out of the box. Know exactly what's happening in production.

  • 15+ Prometheus metrics
  • Zap structured logging
  • Index health monitoring
  • Transaction error tracking
  • Query profiling
Schema Versioning

Evolve Schemas Without Downtime

Add a version field, register migrations, and your data transforms automatically on read. No ALTER TABLE statements, no downtime.

  • Opt-in with _v field
  • Lazy migration on read
  • Automatic version chaining
  • Zero overhead when not used
  • Gradual write-back policy
// 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)

Perfect for "No Database" Applications

If you don't need JOINs or complex aggregations, you probably don't need a database

User Management

Store user profiles, preferences, sessions. No schema migrations when adding new fields.

E-commerce

Orders, invoices, product catalogs. Index by user, status, date without complex queries.

Configuration

App configs, feature flags, tenant settings. Update instantly without migrations.

Content Management

Blog posts, articles, documentation. Store rich JSON without rigid schemas.

Event Logging

Audit trails, activity logs. Append-only JSONL format for efficient writes.

Multi-tenant SaaS

Per-tenant configuration and data. Scale without database partitioning complexity.

Cost Comparison

85% cheaper than managed databases (1TB data, 1M requests/day)

SmarterBase

$41 /month

S3: $23
Requests: $5
Redis: $13

RDS PostgreSQL

$271 /month

Instance: $41
Storage: $115
Backups: $115

DynamoDB

$300 /month

Storage: $250
Read/Write: $50+

MongoDB Atlas

$100 /month

M10 cluster: $57
Storage: $43+

Quick Start

Get started in minutes with Go 1.18+

1

Installation

go get github.com/adrianmcphee/smarterbase
2

Simple API - Quick Start

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")
}
3

Indexing (Core API)

// 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",
)

Documentation

Comprehensive guides and technical documentation