Ballerina ORM

The First ORM for Ballerina

Type-safe data access with annotated records, fluent query building, and an API that feels familiar to Prisma users while staying native to Ballerina.

Query Previewmain.bal
orm:Client db = check new ({
    provider: orm:POSTGRESQL,
    url: "postgresql://localhost:5432/blog"
});

User[] users = check orm:from(User)
    .where({status: {equals: "ACTIVE"}})
    .include({posts: true})
    .take(20)
    .findMany();

Core Features

Designed for fast delivery and safe refactors

Type-safe queries

Generated input and filter types catch invalid query shapes before runtime.

Annotated schema

Your Ballerina record types define schema, columns, keys, indexes, and relations.

MySQL + PostgreSQL

Dialect abstraction with first-class support for both engines from day one.

Fluent API

Immutable method chaining for readable, composable and testable data access code.

Relation support

Handle 1:1, 1:N and M:N relations with include support and nested data patterns.

Raw SQL escape hatch

Use rawQuery and rawExecute when you need handcrafted SQL for edge cases.

Code Showcase

See schema and query code side by side

Schema
@orm:Entity {tableName: "users"}
public type User record {|
    @orm:Id @orm:AutoIncrement
    int id;

    @orm:Column {nullable: false}
    string email;

    string name;
|};
Query
User user = check orm:from(User)
    .create({
        email: "jane@example.com",
        name: "Jane"
    });

Use these patterns as building blocks, then move into full guides in the docs section.

Why Ballerina ORM?

Familiar DX with native Ballerina patterns

Fewer moving parts

Keep schema and domain types in one place using annotations directly on records.

Safer than handwritten SQL

Query shape mistakes are surfaced earlier through typed inputs and compiler feedback.

Escape hatch included

When you need tailored SQL, use raw query APIs without abandoning the ORM workflow.

CapabilityRaw SQLbal persistBallerina ORM
Type-safe query inputManualPartialStrong
Fluent filteringManual SQLLimitedBuilt-in
Relations includesManual joinsBasicRich include API
Raw SQL escape hatchNativeLimitedBuilt-in
Schema source of truthSQL filesPersist modelsAnnotated records

Quick Start

Go from zero to first query in minutes

Step 01

Install

Add the ORM package and configure your database connection.

bal add thambaru/bal_orm

Step 02

Define Schema

Model tables using annotated Ballerina records as your source of truth.

@orm:Entity
public type User record {|
    @orm:Id int id;
|};

Step 03

Query

Run fluent, type-safe queries with filtering, ordering, and includes.

User[] users = check orm:from(User)
    .findMany();

Community

Built in the open with the Ballerina community

This section is a placeholder for usage metrics and testimonials as adoption grows. If you are building with Ballerina ORM, share your project to be featured here.

Community contributors

Growing

Open roadmap items

Active

Early adopter feedback

Welcome