← Back to list

Fedaco: Laravel Eloquent Rebuilt for TypeScript

If you’ve ever wished you could bring Eloquent’s elegance into your Node.js stack, Fedaco is your answer.

quodr3 · 2026-05-22 05:24 · 0 claps · 3.7 min read
#typescript #prisma #eloquent #nestjs #fedaco
Open on Medium ↗
Wiki topics: 🌐 · Web Development

Fedaco: Laravel Eloquent Rebuilt for TypeScript

If you’ve ever wished you could bring Eloquent’s elegance into your Node.js stack, Fedaco is your answer.

For years, Laravel developers have enjoyed one of the most expressive, developer-friendly ORMs in any ecosystem — Eloquent. Its Active Record pattern, fluent query builder, and rich relationship API set a gold standard for how database interactions should feel.

But what happens when you move to TypeScript? You’re met with verbose repository patterns, code-generated schemas, or bare query builders that lack the ergonomics you loved. Until now.

Fedaco brings the full power of Eloquent into TypeScript — decorator-based models, fluent queries, deep relationship support, and production-grade connection management — all without code generation or schema files.

Why Fedaco?

1. Models That Feel Like Home

If you’ve written an Eloquent model, you already know Fedaco:

import {
  Column, CreatedAtColumn, HasManyColumn, Model,
  PrimaryGeneratedColumn, Table, UpdatedAtColumn, forwardRef,
} from '@gradii/fedaco';
@Table({ tableName: 'users' })
export class User extends Model {
  _fillable = ['email', 'name'];
  @PrimaryGeneratedColumn()
  declare id: number;
  @Column()
  declare email: string;
  @Column()
  declare name: string;
  @HasManyColumn({ related: forwardRef(() => Post), foreignKey: 'user_id' })
  public posts: Post[];
  @CreatedAtColumn()
  declare created_at: Date;
  @UpdatedAtColumn()
  declare updated_at: Date;
}

No schema files. No code generation step. Just TypeScript classes with decorators — the way models should be.

2. Queries That Read Like English

Fedaco’s query builder mirrors Eloquent’s fluent API:

// Simple CRUD
const user = await User.createQuery().create({
  email: 'ada@example.com',
  name: 'Ada Lovelace',
});
// Expressive querying
const activeAuthors = await User.createQuery()
  .whereHas('posts', (q) => q.where('views', '>', 1000))
  .where('active', true)
  .orderBy('created_at', 'desc')
  .get();
// Pagination built in
const page = await User.createQuery()
  .where('active', true)
  .paginate(1, 20);

3. Relationships Done Right

This is where Fedaco truly separates itself from the pack. It supports the full Eloquent relationship suite:

  • One-to-One / One-to-Many / Belongs-To — the basics, done well
  • Many-to-Many — with pivot tables, custom pivot models, wherePivot, withPivot
  • Has-One-Through / Has-Many-Through — query across intermediate tables
  • Has One of Many — “latest order”, “highest price” with window-function subqueries
  • Full Polymorphic SuitemorphTo, morphOne, morphMany, morphToMany

And the killer feature: **onQuery hooks** on every relationship. Bake constraints directly into the relation definition:

@HasOneOfManyColumn({
  related: forwardRef(() => Price),
  onQuery: (q) => q.latestOfMany(['published_at', 'id']),
})
public currentPrice: Price;

This runs on every access — eager load, lazy load, or whereHas — ensuring consistent behavior without scattering query logic across your codebase.

4. Eager Loading That Eliminates N+1

const users = await User.createQuery()
  .with('posts')
  .with({ posts: (q) => q.where('published', true) })
  .with('posts.comments.author')
  .get();

Nested eager loading, constrained eager loads, withWhereHas, and even Model.preventLazyLoading() for catching N+1 issues in development.

5. Production-Grade Connection Management

Fedaco isn’t a toy — it handles real-world database topologies:

db.addConnection({
  driver: 'mysql',
  factory: mysqlDriver(),
  database: 'app',
  read: { host: ['replica-a.internal', 'replica-b.internal'] },
  write: { host: 'primary.internal' },
  pool: { max: 20, acquireTimeout: 5000, idleTimeout: 30000 },
});
  • Read/write splitting with sticky writes for read-after-write consistency
  • Connection pooling with configurable limits and timeouts
  • Multiple named connections — per-model or per-query
  • Isolated transactions on dedicated pool connections

6. Transactions With Teeth

await db().transaction(
  async (tx) => {
    const user = await User.createQuery(tx).create({ email: 'bob@example.com', name: 'Bob' });
    await Post.createQuery(tx).create({ user_id: user.id, title: 'Hello World' });
  },
  { isolated: true, isolationLevel: 'SERIALIZABLE', attempts: 3, timeout: 5000 },
);

Nested transactions, deadlock retry, isolation levels, and timeout control — all built in.

7. Migrations Included

No need for a separate migration tool. Fedaco ships with a Laravel-style migration CLI:

fedaco migrate:make create_users_table --create users
fedaco migrate
fedaco migrate:rollback
fedaco migrate:fresh
fedaco migrate:status

And a fluent schema builder:

await schema().create('users', (table) => {
  table.increments('id');
  table.string('email').withUnique();
  table.string('name').nullable();
  table.timestamps();
});

8. Framework Integrations

NestJS gets first-class support with lifecycle management, graceful shutdown, and pool teardown:

import { FedacoModule } from '@gradii/nest-fedaco';
@Module({
  imports: [
    FedacoModule.forRoot({
      default: {
        driver: 'sqlite',
        factory: sqliteDriver(),
        database: './data/app.sqlite',
        pool: { max: 10 },
      },
    }),
  ],
})
export class AppModule {}

Midway framework is also supported via @gradii/midway-fedaco.

9. Multi-Database Support

Fedaco supports all the databases you need through pluggable driver packages:

The core ORM stays lean — install only the driver you need. You can even build custom drivers for unsupported databases.

Who Is Fedaco For?

  • Laravel/PHP teams moving to TypeScript — Keep your Eloquent muscle memory
  • NestJS developers — Get a proper Active Record ORM with native integration
  • Teams building complex data models — Polymorphic relations, pivot tables, and eager loading that actually works
  • Production apps needing connection control — Read/write split, pooling, and isolated transactions out of the box

Getting Started

npm install @gradii/fedaco @gradii/fedaco-sqlite-driver
import { DatabaseConfig } from '@gradii/fedaco';
import { betterSqliteDriver } from '@gradii/fedaco-sqlite-driver';
const db = new DatabaseConfig();
db.addConnection({
  driver: 'sqlite',
  factory: betterSqliteDriver(),
  database: './tmp/app.sqlite',
});
db.bootFedaco();
db.setAsGlobal();

That’s it. Define your models, run your queries, and enjoy Eloquent — in TypeScript.

Documentation: gradii.github.io/fedaco GitHub: github.com/gradii/fedaco Examples: github.com/gradii/fedaco-examples

Fedaco vs. Prisma vs. TypeORM: How They Compare

The Bottom Line

Choose Prisma if you want best-in-class TypeScript type safety with auto-generated types and don’t need advanced relationship patterns. You’ll pay the cost of a build step, an external engine binary, and limited relationship expressiveness.

Choose TypeORM if you need broad database support and want flexibility between Active Record and Data Mapper patterns. But expect to fight relationship loading issues and deal with a less cohesive API surface.

Choose Fedaco if you want Eloquent’s battle-tested API design in TypeScript — deep relationships (including polymorphic and has-one-of-many), production-ready connection management, and zero code generation. Especially compelling for teams coming from Laravel or building complex domain models in NestJS.

Fedaco is open-source under the MIT license. Star it on GitHub and join the community.


메타데이터
post_id
7e73d461a494
slug
fedaco-laravel-eloquent-rebuild-for-typescript-7e73d461a494
url
https://medium.com/@quodr3/fedaco-laravel-eloquent-rebuild-for-typescript-7e73d461a494
canonical_url
https://medium.com/@quodr3/fedaco-laravel-eloquent-rebuild-for-typescript-7e73d461a494
author_url
https://medium.com/@quodr3
status
ok
fetched_at
2026-06-09 15:37:30