Documentation
Getting Started
From zero to querying your first table in under 10 minutes.
Requirements
- Unity 2021.3 LTS or newer
- Scripting Backend: Mono or IL2CPP
- API Compatibility:
.NET Standard 2.1 - Platforms: Windows, macOS, Linux, Android, iOS, WebGL (Editor always on Windows or macOS)
- Bundled: gilzoide/unity-sqlite-net native plugin — provides the SQLite3 binary for Windows, macOS, Linux, and Android. iOS and WebGL use Unity's built-in SQLite and do not need the extra native lib.
- Optional: Unity Addressables package — only needed for
AssetRef<T>loading helpers. Enable viaWindow → GameSchema → Welcome → Modules.
Installation
- 1Copy the
Assets/Plugins/Databasefolder into your Unity project. - 2Open the Welcome window: Window → GameSchema → Welcome. This verifies the install and lets you enable optional modules (e.g. Addressables).
- 3Commit the
.gameschemasettings file (created alongside your.db) to version control so all teammates share the same configuration.
Tip: The
.db file itself lives in StreamingAssets/. Commit it too — the editor uses journal_mode=DELETE so it stays clean for VCS.Opening the Editor
Open the Database Editor via Window → GameSchema → Database Editor. From here you can:
- Create and rename tables
- Add columns with types (
INTEGER,TEXT,REAL,BLOB), constraints (NOT NULL, PRIMARY KEY), and foreign key references - Edit row data in a spreadsheet-style view
- Drag Unity assets onto AssetRef columns (Addressables integration)
- View the ERD diagram: Window → GameSchema → ERD
- Validate the schema: Window → GameSchema → Validation
Code Generation
GameSchema generates two C# files per table — a data class and a static query class. They give you typed access to every column without ever writing a string.
- 1In the Database Editor, go to the Settings tab.
- 2Set
Code Gen Directory(e.g.Assets/Scripts/Generated). - 3Click Generate Code. Unity will compile the output automatically.
The generated files look like this (abbreviated):
EnemyData.cs (generated)
// Generated by GameSchema — do not edit
[Table("enemies")]
public class EnemyData
{
[PrimaryKey]
public int Id;
[NotNull]
public string Name;
public int Level;
[ForeignKey("weapons")]
public int WeaponId;
}Enemies.cs (generated)
// Generated by GameSchema — do not edit
public static class Enemies
{
// Typed column references (no magic strings needed in queries)
public static readonly Column<int> Id = new("id");
public static readonly Column<string> Name = new("name");
public static readonly Column<int> Level = new("level");
public static readonly Column<int> WeaponId = new("weapon_id");
// Simple one-liners
public static EnemyData Get(int id) { ... }
public static List<EnemyData> GetAll(Condition filter = null) { ... }
public static int Count(Condition filter = null) { ... }
// Query builder entry points
public static TypedQuery<EnemyData> Query() { ... }
public static TypedQuery<EnemyData> From(int id){ ... }
}Tip: Enable Serializable in the Settings tab to add
[Serializable] to generated data classes — useful if you want to inspect them in the Unity Inspector.Runtime Initialization
Call DB.Initialize() exactly once at startup, before any queries run. A boot MonoBehaviour or a [RuntimeInitializeOnLoadMethod] are both good choices.
BootstrapManager.cs
using GameSchema;
public class BootstrapManager : MonoBehaviour
{
void Awake()
{
// Opens StreamingAssets/game.db (read-only at runtime)
DB.Initialize();
}
void OnDestroy()
{
DB.Shutdown();
}
}// Use a different filename
DB.Initialize("world.db");Note:
DB.Initialize() opens StreamingAssets/game.db read-only at runtime. On Android and WebGL the file is automatically copied to persistentDataPath on first launch.Your First Query
Once the database is initialized, every generated table class is ready to use from anywhere in your code — no dependency injection required.
EnemySpawner.cs
// Get a single row by primary key
var boss = Enemies.Get(42);
Debug.Log(boss.Name); // "Dragon King"
// Get all rows matching a condition
var toughEnemies = Enemies.GetAll(Enemies.Level > 5);
foreach (var e in toughEnemies)
Debug.Log($"{e.Name} Lv.{e.Level}");
// Count without fetching rows
int count = Enemies.Count(Enemies.Level > 5);That's it. No SQL, no raw strings, full IntelliSense.
Next steps
- Simple Methods → Get, GetAll, Count in detail
- TypedQuery Builder → Chaining Where, OrderBy, Limit, and more
- FK Navigation → Traverse foreign key relationships
- Best Practices → When to use JOINs vs navigation, performance tips