Skip to main content
In this .NET quickstart you will learn how to:
  • Retrieve database credentials
  • Install the Bunny.LibSQL.Client package
  • Connect to a remote Bunny Database
  • Define models and run migrations
  • Execute queries using LINQ
While foundational ORM and querying features are available, several enhancements are still in progress. You can report issues, contribute, or learn more on GitHub.

Quickstart

1

Retrieve database credentials

You will need an existing database to continue. If you don’t have one, create one.Navigate to Dashboard > Edge Platform > Database > [Select Database] > Access to find your database URL and generate an access token.
You should store these as environment variables to keep them secure.
2

Install Bunny.LibSQL.Client

Install the package via NuGet:
dotnet add package Bunny.LibSql.Client
3

Define your database

Create a database context class that inherits from LibSqlDbContext:
public class AppDb : LibSqlDbContext
{
    public AppDb(string dbUrl, string accessKey)
        : base(new LibSqlClient(dbUrl, accessKey)) {}

    public LibSqlTable<User> Users { get; set; }
}
4

Define your models

Create model classes with attributes to define the table structure:
[Table("Users")]
public class User
{
    [Key]
    public int id { get; set; }

    [Index]
    public string name { get; set; }

    public string email { get; set; }
}
5

Initialize and migrate

Create an instance of your database context and apply migrations:
var db = new AppDb(
    Environment.GetEnvironmentVariable("DB_URL"),
    Environment.GetEnvironmentVariable("DB_TOKEN")
);

await db.ApplyMigrationsAsync();
6

Execute a query

You can query your database using LINQ:
var users = await db.Users.ToListAsync();

foreach (var user in users)
{
    Console.WriteLine($"User: {user.name}");
}

Managing Records

Insert

Insert records using InsertAsync:
await db.Users.InsertAsync(new User
{
    id = 1,
    name = "Kit",
    email = "kit@example.com"
});

Update

Update records using UpdateAsync:
var user = await db.Users.Where(u => u.id == 1).FirstOrDefaultAsync();
user.name = "Kit Updated";
await db.Users.UpdateAsync(user);

Delete

Delete records using DeleteAsync:
var user = await db.Users.Where(u => u.id == 1).FirstOrDefaultAsync();
await db.Users.DeleteAsync(user);

Querying with LINQ

Basic Query

var users = await db.Users
    .Where(u => u.name.StartsWith("K"))
    .ToListAsync();

Eager Loading with Include

Load related entities using Include():
var usersWithOrders = await db.Users
    .Include(u => u.Orders)
    .ToListAsync();

Aggregates

Perform aggregate queries with CountAsync() and SumAsync():
var userCount = await db.Users.CountAsync();
var totalPrice = await db.Orders.SumAsync(o => o.price);
Always use the Async variants like ToListAsync(), CountAsync(), and SumAsync() to execute queries. Skipping the async call will not run the query.

Transactions

Use transactions to group multiple operations together:
await db.Client.BeginTransactionAsync();

try
{
    await db.Users.InsertAsync(new User
    {
        name = "Kit",
        email = "kit@example.com"
    });

    await db.Users.InsertAsync(new User
    {
        name = "Sam",
        email = "sam@example.com"
    });

    await db.Client.CommitTransactionAsync();
}
catch
{
    await db.Client.RollbackTransactionAsync();
    throw;
}

Direct SQL Queries

For raw SQL access, use the underlying client directly.

Run a command

await db.Client.QueryAsync("DELETE FROM Users WHERE id = 1");

Get a scalar value

var count = await db.Client.QueryScalarAsync<int>("SELECT COUNT(*) FROM Users");

Model Attributes

AttributeDescription
TableSpecifies a custom table name for the entity. If omitted, class name is used.
KeyMarks the property as the primary key of the table.
IndexCreates an index on the annotated property for faster lookups.
ForeignKeyDefines a relationship to another table by specifying the foreign key property.
AutoIncludeEnables eager loading of the related property automatically during queries.
UniqueMarks the field with the UNIQUE constraint, ensuring a unique value in every row.
ManyToManyDefines a many-to-many relationship through a join table.

Supported Data Types

C# TypeDescriptionSQLite Type
stringTextual dataTEXT
int32-bit integerINTEGER
long64-bit integerINTEGER
doubleDouble-precision floating pointREAL
floatSingle-precision floating pointREAL
decimalDecimal numberREAL
DateTimeDate and timeINTEGER (UNIX timestamp)
boolBoolean valueINTEGER (0 or 1)
byte[]Binary dataBLOB
F32BlobVector F32 blob (AI embeddings)F32_BLOB
Nullable variants (e.g., int?, bool?) are also supported and will map to nullable columns.

Relationships

Define relationships between models using attributes:
[Table("Users")]
public class User
{
    [Key]
    public int id { get; set; }

    public string name { get; set; }

    [AutoInclude]
    public List<Order> Orders { get; set; } = new();
}

[Table("Orders")]
public class Order
{
    [Key]
    public int id { get; set; }

    [ForeignKeyFor(typeof(User))]
    public int user_id { get; set; }

    public decimal price { get; set; }
}
Query with relationships:
var users = await db.Users
    .Include(u => u.Orders)
    .ToListAsync();

foreach (var user in users)
{
    Console.WriteLine($"User: {user.name}");
    foreach (var order in user.Orders)
    {
        Console.WriteLine($"  Order: {order.price}");
    }
}