{"id":47978734,"url":"https://github.com/zoobz-io/grub","last_synced_at":"2026-04-04T10:59:38.398Z","repository":{"id":331978177,"uuid":"1118413222","full_name":"zoobz-io/grub","owner":"zoobz-io","description":"Provider-agnostic storage for Go","archived":false,"fork":false,"pushed_at":"2026-03-29T16:51:04.000Z","size":677,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-04T10:59:32.185Z","etag":null,"topics":["blob","database","go","golang","kv","storage","vector","zoobzio"],"latest_commit_sha":null,"homepage":"https://grub.zoobz.io","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zoobz-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-17T18:03:40.000Z","updated_at":"2026-03-29T16:45:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/zoobz-io/grub","commit_stats":null,"previous_names":["zoobzio/grub","zoobz-io/grub"],"tags_count":145,"template":false,"template_full_name":null,"purl":"pkg:github/zoobz-io/grub","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoobz-io%2Fgrub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoobz-io%2Fgrub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoobz-io%2Fgrub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoobz-io%2Fgrub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zoobz-io","download_url":"https://codeload.github.com/zoobz-io/grub/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoobz-io%2Fgrub/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31397056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blob","database","go","golang","kv","storage","vector","zoobzio"],"created_at":"2026-04-04T10:59:37.513Z","updated_at":"2026-04-04T10:59:38.379Z","avatar_url":"https://github.com/zoobz-io.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# grub\n\n[![CI](https://github.com/zoobz-io/grub/actions/workflows/ci.yml/badge.svg)](https://github.com/zoobz-io/grub/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/zoobz-io/grub/graph/badge.svg?branch=main)](https://codecov.io/gh/zoobz-io/grub)\n[![Go Report Card](https://goreportcard.com/badge/github.com/zoobz-io/grub)](https://goreportcard.com/report/github.com/zoobz-io/grub)\n[![CodeQL](https://github.com/zoobz-io/grub/actions/workflows/codeql.yml/badge.svg)](https://github.com/zoobz-io/grub/actions/workflows/codeql.yml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/zoobz-io/grub.svg)](https://pkg.go.dev/github.com/zoobz-io/grub)\n[![License](https://img.shields.io/github/license/zoobz-io/grub)](LICENSE)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/zoobz-io/grub)](go.mod)\n[![Release](https://img.shields.io/github/v/release/zoobz-io/grub)](https://github.com/zoobz-io/grub/releases)\n\nProvider-agnostic storage for Go.\n\nType-safe CRUD across key-value stores, blob storage, SQL databases, and vector similarity search with a unified interface.\n\n## One Interface, Any Backend\n\n```go\n// Same code, different providers\nsessions := grub.NewStore[Session](redis.New(client))\nsessions := grub.NewStore[Session](badger.New(db))\nsessions := grub.NewStore[Session](bolt.New(db, \"sessions\"))\n\n// Type-safe operations\nsession, _ := sessions.Get(ctx, \"session:abc\")\nsessions.Set(ctx, \"session:xyz\", \u0026Session{UserID: \"123\"}, time.Hour)\n```\n\nSwap Redis for BadgerDB. Move from S3 to Azure. Switch databases from SQLite to PostgreSQL. Your business logic stays the same.\n\n```go\n// Key-value, blob, SQL, or vector — same patterns\nstore := grub.NewStore[Config](provider)           // key-value\nbucket := grub.NewBucket[Document](provider)       // blob storage\ndb := grub.NewDatabase[User](conn, \"users\", renderer)            // SQL\nindex := grub.NewIndex[Embedding](provider)        // vector search\n```\n\nFour storage modes, consistent API, semantic errors across all providers.\n\n## Install\n\n```bash\ngo get github.com/zoobz-io/grub\n```\n\nRequires Go 1.24+.\n\n## Quick Start\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"time\"\n\n    \"github.com/zoobz-io/grub\"\n    \"github.com/zoobz-io/grub/redis\"\n    goredis \"github.com/redis/go-redis/v9\"\n)\n\ntype Session struct {\n    UserID    string `json:\"user_id\"`\n    Token     string `json:\"token\"`\n    ExpiresAt int64  `json:\"expires_at\"`\n}\n\nfunc main() {\n    ctx := context.Background()\n\n    // Connect to Redis\n    client := goredis.NewClient(\u0026goredis.Options{Addr: \"localhost:6379\"})\n    defer client.Close()\n\n    // Create type-safe store\n    sessions := grub.NewStore[Session](redis.New(client))\n\n    // Store with TTL\n    session := \u0026Session{\n        UserID:    \"user:123\",\n        Token:     \"abc123\",\n        ExpiresAt: time.Now().Add(24 * time.Hour).Unix(),\n    }\n    _ = sessions.Set(ctx, \"session:abc123\", session, 24*time.Hour)\n\n    // Retrieve\n    s, _ := sessions.Get(ctx, \"session:abc123\")\n    fmt.Println(s.UserID) // user:123\n}\n```\n\n## Capabilities\n\n| Feature         | Description                                        | Docs                                           |\n| --------------- | -------------------------------------------------- | ---------------------------------------------- |\n| Key-Value Store | Sessions, cache, config with optional TTL          | [Providers](docs/3.guides/1.providers.md)      |\n| Blob Storage    | Files and documents with metadata                  | [Lifecycle](docs/3.guides/2.lifecycle.md)      |\n| SQL Database    | Structured records with query capabilities         | [Concepts](docs/2.learn/2.concepts.md)         |\n| Vector Search   | Similarity search with metadata filtering          | [Providers](docs/3.guides/1.providers.md)      |\n| Atomic Views    | Field-level access for encryption pipelines        | [Architecture](docs/2.learn/3.architecture.md) |\n| Semantic Errors | `ErrNotFound`, `ErrDuplicate` across all providers | [API Reference](docs/5.reference/1.api.md)     |\n| Custom Codecs   | JSON default, Gob available, or bring your own     | [Concepts](docs/2.learn/2.concepts.md)         |\n\n## Why grub?\n\n- **Type-safe** — Generics eliminate runtime type assertions\n- **Swap backends** — Change providers without touching business logic\n- **Consistent errors** — Same error types whether you're using Redis or S3\n- **Atomic views** — Field-level access for framework internals (encryption, pipelines)\n- **Isolated dependencies** — Each provider is a separate module; only pull what you use\n\n## Storage Without Coupling\n\nGrub enables a pattern: **define storage once, swap implementations freely**.\n\nYour domain code works with typed stores. Infrastructure decisions — Redis vs embedded, S3 vs local filesystem, PostgreSQL vs SQLite, Pinecone vs Qdrant — become configuration, not architecture.\n\n```go\n// Domain code doesn't know or care about the backend\ntype SessionStore struct {\n    store *grub.Store[Session]\n}\n\nfunc (s *SessionStore) Save(ctx context.Context, session *Session) error {\n    return s.store.Set(ctx, \"session:\"+session.Token, session, 24*time.Hour)\n}\n\n// Production: Redis\nstore := grub.NewStore[Session](redis.New(redisClient))\n\n// Development: embedded BadgerDB\nstore := grub.NewStore[Session](badger.New(localDB))\n\n// Testing: in-memory\nstore := grub.NewStore[Session](badger.New(memDB))\n```\n\nOne interface. Any backend. Zero vendor lock-in.\n\n## Documentation\n\n- [Overview](docs/1.overview.md) — Design philosophy and architecture\n\n### Learn\n\n- [Quickstart](docs/2.learn/1.quickstart.md) — Get started in minutes\n- [Core Concepts](docs/2.learn/2.concepts.md) — Stores, buckets, databases, codecs\n- [Architecture](docs/2.learn/3.architecture.md) — Layer model, atomic views, concurrency\n\n### Guides\n\n- [Providers](docs/3.guides/1.providers.md) — Setup and configuration for all backends\n- [Lifecycle](docs/3.guides/2.lifecycle.md) — CRUD operations and batch processing\n- [Pagination](docs/3.guides/3.pagination.md) — Listing and iterating large datasets\n- [Testing](docs/3.guides/4.testing.md) — Mocks, embedded DBs, testcontainers\n- [Best Practices](docs/3.guides/5.best-practices.md) — Key design, error handling, performance\n\n### Cookbook\n\n- [Caching](docs/4.cookbook/1.caching.md) — Cache-aside, read-through, TTL strategies\n- [Migrations](docs/4.cookbook/2.migrations.md) — Switching providers without downtime\n- [Multi-Tenant](docs/4.cookbook/3.multi-tenant.md) — Tenant isolation patterns\n\n### Reference\n\n- [API](docs/5.reference/1.api.md) — Complete API documentation\n- [Providers](docs/5.reference/2.providers.md) — Provider-specific behaviors and limitations\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n## License\n\nMIT License — see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzoobz-io%2Fgrub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzoobz-io%2Fgrub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzoobz-io%2Fgrub/lists"}