Skip to content

Getting Started

František Bereň edited this page Sep 18, 2026 · 3 revisions

Getting Started

Working CRUD against a real SQLite database, in about ten minutes. Every snippet below was compiled and run before being written down.

1. Get the source

Birko is consumed as source, not NuGet. Clone it next to your own project:

C:\Source\Birko\
├── Framework\          ← git clone https://github.com/Birko-Framework/Birko.Framework.git
└── Consumers\
    └── MyApp\          ← your project

That layout matters — the default path resolution below assumes your project sits two levels under a folder that also contains Framework. Any layout works if you set BIRKO_SRC (see step 2).

2. Tell your project where Birko is

Create Directory.Build.props at the root of your repo:

<Project>
  <PropertyGroup>
    <!-- 1. /p:BirkoSrc=... on the CLI   2. BIRKO_SRC env var   3. the default below -->
    <BirkoSrc Condition="'$(BirkoSrc)' == '' and '$(BIRKO_SRC)' != ''">$(BIRKO_SRC)</BirkoSrc>
    <BirkoSrc Condition="'$(BirkoSrc)' == ''">$(MSBuildThisFileDirectory)..\..\Framework</BirkoSrc>
  </PropertyGroup>
</Project>

Three ways to point at the framework, in priority order, so CI and Docker can override it without editing files.

3. Create an aggregator project

⚠️ This is the step people get wrong. Do not build the list up one project at a time. The graph is dense — importing SQLite stores also needs models, view-models, patterns, rules and helpers — and you discover that one compiler error at a time. (Measured: ten rounds of adding a project and rebuilding, still not closed.)

Start from a list that is known to compile and delete what you do not use:

  • Birko.Sandbox's app csproj — 38 imports, covering stores, SQL, migrations, caching, workflow, jobs, health, REST, GraphQL and security. This is the better starting point for most applications.
  • Birko.Sandbox's compile gate — 163 imports, i.e. nearly everything. Use it if you would rather delete than add.

Make one project that imports Birko, and have your other projects reference it:

MyApp/
├── Directory.Build.props      ← step 2
├── MyApp.Birko/               ← the aggregator: imports Birko, nothing else
│   └── MyApp.Birko.csproj
└── MyApp.Api/                 ← your code: <ProjectReference> to MyApp.Birko

The aggregator looks like this — abbreviated; take the real list from the link above:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <Import Project="$(BirkoSrc)\Birko.Contracts\Birko.Contracts.projitems" Label="Shared" />
  <Import Project="$(BirkoSrc)\Birko.Configuration\Birko.Configuration.projitems" Label="Shared" />
  <Import Project="$(BirkoSrc)\Birko.Data.Core\Birko.Data.Core.projitems" Label="Shared" />
  <Import Project="$(BirkoSrc)\Birko.Data.Stores\Birko.Data.Stores.projitems" Label="Shared" />
  <Import Project="$(BirkoSrc)\Birko.Data.SQL\Birko.Data.SQL.projitems" Label="Shared" />
  <Import Project="$(BirkoSrc)\Birko.Data.SQL.SqLite\Birko.Data.SQL.SqLite.projitems" Label="Shared" />
  <!-- … and the rest -->
</Project>

Why one aggregator? If several projects import overlapping .projitems directly, the same types get compiled into multiple assemblies and you get duplicate-type errors. One aggregator, referenced normally, avoids that.

💡 You do not declare Birko's NuGet packages. Each .projitems brings its own (Microsoft.Data.Sqlite and so on). Declaring them yourself produces duplicate-PackageReference warnings.

4. Write a model

using Birko.Data.Models;
using Birko.Data.SQL.Attributes;

[Table("Products")]
public class Product : AbstractDatabaseModel
{
    [MaxLengthField(200)]
    public string Name { get; set; } = string.Empty;

    [PrecisionField(18), ScaleField(2)]
    public decimal Price { get; set; }
}

AbstractDatabaseModel gives you a Guid primary key. The table is created automatically on first use — no migration needed to get started.

Attributes that exist (there is no DecimalField — precision and scale are separate):

Attribute Does
[Table("name")] table name
[MaxLengthField(n)] VARCHAR(n) instead of unbounded text
[PrecisionField(p)], [ScaleField(s)] DECIMAL(p,s) — use both, or you get whole numbers
[RequiredField] NOT NULL
[UniqueField], [PrimaryField] constraints
[IndexedField("ix_name")], [CompositeIndex(...)] indexes — both take a name
[UtcField] store a DateTime as a true instant, read back as UTC
[NamedField("col")] different column name
[IgnoreField] don't persist this property

5. Use it

using Birko.Data.SQL.SqLite.Stores;

var store = new SQLiteStore<Product>();
store.SetSettings(new SqLiteSettings(@"C:\data", "shop.db"));

// create
var id = store.Create(new Product { Name = "Widget", Price = 9.99m });

// read one
var product = store.Read(id);

// query
var cheap = store.Read(x => x.Price < 10m, null, null, null);   // filter, orderBy, limit, offset

// update
product!.Price = 12.50m;
store.Update(product);

// count and delete
var total = store.Count();
store.Delete(product);

That is the whole loop. Output from running exactly this:

created:  True
read:     Widget
filtered: Widget
count:    2

💡 SqLiteSettings lives in Birko.Data.SQL.SqLite.Stores, not Birko.Configuration — the settings class ships with its provider.

6. Try another backend

The point of the store API is that this swaps cleanly. Same model, same calls:

using Birko.Data.InMemory.Stores;

var store = new InMemoryStore<Product>();   // no settings needed — ideal for tests

InMemoryStore is the simplest backend and the recommended test double. See Data and Stores for the full list and what each is good for.

Common first problems

Symptom Cause
CS0246: type X could not be found for framework types Missing .projitems import. Take the full list from the Sandbox aggregator rather than adding one at a time.
Duplicate type errors Two of your projects import the same .projitems. Use a single aggregator.
NU1504 duplicate PackageReference You declared a package the .projitems already brings. Remove yours.
Decimals stored as whole numbers [PrecisionField] without [ScaleField]. Both are required.
Build works locally, fails in CI BirkoSrc resolving elsewhere. Set BIRKO_SRC explicitly in CI.

Where next


Accuracy note

Some documents in the repository are out of date and contradict this page. Where they differ:

  • Birko.Data.SQL.SqLite/CLAUDE.md lists three dependencies; it actually needs at least eight.
  • README.md suggests copying "the shared projects you need" — in practice that does not converge.
  • PREZENTACIA.md project counts predate a large reorganisation.

Clone this wiki locally