This is a library management application showcasing RavenDB features, built with:
- Backend: .NET 10 + Azure Functions + RavenDB 7.1
- Frontend: SvelteKit 2 + TypeScript + Vite
- Orchestration: .NET Aspire 13.0
- Data: Goodbooks-10k dataset (git submodule)
The app demonstrates:
- Vector Search for finding similar books
- Document Refresh for timeout handling
- Azure Storage Queues ETL for notifications
- Aspire for local development orchestration
src/
├── RavenDB.Samples.Library.AppHost/ # Aspire orchestration host
├── RavenDB.Samples.Library.App/ # Azure Functions API backend
├── RavenDB.Samples.Library.Frontend/ # SvelteKit web frontend
├── RavenDB.Samples.Library.Model/ # Shared data models & indexes
├── RavenDB.Samples.Library.Setup/ # Database migrations
└── RavenDB.Samples.Library.ServiceDefaults/ # Aspire service defaults
AppHost (AppHost.cs):
- Configures RavenDB server and database ("library")
- Sets up Azure Storage emulator for queues
- Orchestrates Functions app and npm frontend
- Defines migration command with HTTP trigger
- Uses Aspire service discovery
API Backend (RavenDB.Samples.Library.App):
- Azure Functions with isolated worker model (.NET 10)
- HTTP triggers for RESTful endpoints
- Key endpoints:
GET /api/books/{id}- Fetch book with author (uses Include)GET /api/authors/{id}- Fetch author with books (uses LazilyAsync)GET /api/search- Full-text search via GlobalSearchIndexGET /api/home/books- Random books for homepageGET /api/user/profile- User borrowed booksPOST /api/user/borrow- Borrow a bookPOST /api/user/return- Return a bookPOST /api/migrate- Run database migrations (admin command)
- Uses RavenDB AsyncDocumentSession for all operations
- Implements HTTP caching via ETag and Last-Modified headers
- CORS enabled for local development
Data Models:
Book- Book metadata (title, author reference)Author- Author info (first/last name)BookEdition- Specific edition of a bookBookCopy- Physical copy available for borrowingUser- Library userUserBook- Junction for borrowed books- All models implement
IRootand use staticBuildId()methods
RavenDB Indexes:
GlobalSearchIndex- Multi-map index for searching books and authorsBooksByAuthor- Books grouped by authorBorrowedBooksByUserIdIndex- User's borrowed books
Frontend (SvelteKit):
- Routes:
/- Homepage with random books/books/{id}- Book details/authors/{id}- Author details with books list/profile- User profile with borrowed books
- Services layer (
lib/services/) for API calls - Shared components (
lib/components/):BookCard.svelte- Book display cardSearchModal.svelte- Search overlayTipBox.svelte- Helpful tips display
- User ID stored in localStorage and sent via
X-User-Idheader
Migrations (RavenDB.Samples.Library.Setup):
- Migration 001: Import Goodbooks-10k dataset from CSV
- Creates authors, books, editions, and copies
- Uses RavenDB bulk insert for performance
- CSV embedded as resource from goodbooks submodule
- Migration 002: Create indexes
- Deploys all custom indexes to database
- .NET 10
- Azure Functions Worker 2.51.0
- RavenDB.Client 7.1.4
- RavenMigrations 6.0.2
- Aspire.Hosting 13.0.1
- CommunityToolkit.Aspire.RavenDB 13.0.0
- Node.js 22.x
- SvelteKit 2.49.0
- Svelte 5.45.2
- TypeScript 5.9.3
- Vite 7.2.6
- Vitest 4.0.14 (testing)
- Playwright 1.57.0 (browser testing)
- ESLint 9.39.1 + Prettier 3.7.3
- .NET Aspire 13.0.1
- Azure Storage (Emulator for local dev)
- RavenDB 6.2+ (via Aspire community toolkit)
-
Clone repository with submodules:
git clone --recursive https://github.com/ravendb/samples-library.git cd samples-libraryOr if already cloned:
git submodule update --init --recursive
-
Restore dependencies:
cd src dotnet restore RavenDB.Samples.Library.sln -
Frontend dependencies:
cd RavenDB.Samples.Library.Frontend npm install cd ..
Start the application via Aspire:
cd src/RavenDB.Samples.Library.AppHost
dotnet runThis will:
- Start RavenDB server
- Launch Azure Storage Emulator
- Start the Functions backend
- Start the Svelte frontend dev server
- Open Aspire dashboard (usually at http://localhost:15000)
Access the application:
- Frontend: Check Aspire dashboard for assigned port
- Backend API: Check Aspire dashboard for Functions endpoint
- RavenDB Studio: Check Aspire dashboard for RavenDB management URL
Run database migrations:
- In Aspire dashboard, use the "Migrate DB" command button
- Or via HTTP:
POST /api/migratewith headerX-Command-Key: <your-secret>
Backend build:
cd src
dotnet build RavenDB.Samples.Library.slnFrontend build:
cd src/RavenDB.Samples.Library.Frontend
npm run buildFrontend linting:
npm run lint
npm run format # auto-fix with PrettierFrontend testing:
npm test # run tests once
npm run test:unit # run tests in watch mode-
Include Pattern - Avoid N+1 queries:
var book = await session .Include<Book>(b => b.AuthorId) .LoadAsync<Book>(id); var author = await session.LoadAsync<Author>(book.AuthorId); // No DB call!
-
Lazy Loading - Batch multiple queries:
var lazyBooks = session.Query<Book>() .Where(b => b.AuthorId == authorId) .LazilyAsync(); var author = await session.LoadAsync<Author>(authorId); var books = await lazyBooks.Value; // Both requests sent together
-
Bulk Insert - Efficient data import:
using var bulkInsert = DocumentStore.BulkInsert(); bulkInsert.Store(entity);
-
Static Indexes - Predefined for performance:
public class BooksByAuthor : AbstractIndexCreationTask<Book> { // Index definition }
-
HTTP Caching - ETag-based caching:
return req.TryCachePublicly(result, session, entities...);
C# (Backend):
- Use top-level statements where appropriate
- Primary constructors for dependency injection
- Static methods for ID builders:
Book.BuildId(id) - Async/await for all I/O operations
- Nullable reference types enabled
TypeScript/Svelte (Frontend):
- Svelte 5 runes syntax (
$state,$derived, etc.) - Services pattern for API calls
- Type-safe API responses
- ESLint + Prettier for code formatting
Backend:
- API endpoints:
Api.{Entity}.cs(e.g.,Api.User.cs) - Models:
{EntityName}.csin Model project - Indexes:
{Name}Index.csinModel/Indexes/ - Migrations:
{Number}_{Description}.cs
Frontend:
- Routes:
+page.svelte,+layout.svelte - Components:
{ComponentName}.svelte - Services:
{entity}.tsinlib/services/ - Tests:
{filename}.spec.ts
- No unit tests currently in solution
- Testing done via:
- Aspire dashboard for integration testing
- Manual API testing via frontend
- Migration validation
- Unit tests with Vitest
- Component tests with
@vitest/browser+ Playwright - Run:
npm testornpm run test:unit - Test files:
*.spec.tsnext to source files
Cause: Goodbooks submodule not initialized Solution:
git submodule update --init --recursiveCause: RavenDB server not started or wrong connection string Solution:
- Ensure Aspire AppHost is running
- Check Aspire dashboard for RavenDB status
- Verify connection string in
appsettings.json
Cause: Dependencies not installed Solution:
cd src/RavenDB.Samples.Library.Frontend
npm installCause: Database already has data from previous run Solution: Delete RavenDB data directory or use new database name
Cause: Aspire-assigned ports already in use Solution: Stop other services or restart Aspire (ports are dynamic)
GitHub Actions (.github/workflows/build.yml):
- Triggers on push/PR to
mainbranch - Two jobs:
- backend: Build .NET solution
- frontend: Build SvelteKit app (currently incomplete in workflow)
Environment Variables:
NODE_VERSION: 22.xDOTNET_VERSION: 10.0.x
- RavenDB Documentation
- .NET Aspire Documentation
- SvelteKit Documentation
- Azure Functions Documentation
- Goodbooks-10k Dataset
# Clone with submodules
git clone --recursive https://github.com/ravendb/samples-library.git
# Or init submodules after clone
git submodule update --init --recursive
# Restore .NET dependencies
cd src && dotnet restore
# Build backend
dotnet build src/RavenDB.Samples.Library.sln
# Install frontend dependencies
cd src/RavenDB.Samples.Library.Frontend && npm install
# Run application (from src/RavenDB.Samples.Library.AppHost)
dotnet run
# Format frontend code
cd src/RavenDB.Samples.Library.Frontend && npm run format
# Lint frontend
npm run lint
# Test frontend
npm test
# Check git status (disable pager)
git --no-pager status
# View changes (disable pager)
git --no-pager diffThis is a sample/demo application designed to showcase RavenDB features in a real-world scenario. It's intended as a learning resource and reference implementation for developers exploring RavenDB with modern .NET and web technologies.
The application uses the Goodbooks-10k dataset, which contains 10,000 books from Goodreads, to provide realistic data for demonstration purposes.
Key learning goals:
- Understanding RavenDB's document model
- Implementing efficient query patterns (Include, Lazy)
- Using RavenDB indexes for search and filtering
- Integrating RavenDB with modern .NET stack
- Building full-stack applications with Aspire orchestration