Skip to content
v1.1 · MIT · Node · Bun · Lambda · Cloudflare · AI-Native

The Laravelexperience.Now in Node.js.

A full-stack TypeScript backend framework with routing, ORM, queues, auth, real-time, and AI agents. All wired up. Conventions in place. Ready on day one.

25packages
100%TypeScript
4runtimes
AInative
~ / my-app
Why FaberJS

Three things you'll never
need to think about again.

Zero config

Auto-discovered. Auto-wired.

Controllers, services, providers — all auto-resolved from the IoC container. Drop a file in the right folder, it just works.

Zero translation

Laravel patterns. Native TypeScript.

Route → Controller → Service → Model. Every Laravel idiom maps 1:1 — Eloquent queries, FormRequests, Policies, Events. Type-safe end-to-end.

Zero limits

AI-native. Multi-runtime.

Built-in agents with tool schemas and streaming. Deploy to Node, Bun, Lambda, or Cloudflare Workers without rewriting a single route.

Zero mental translation

If you've built with Laravel,
you already speak FaberJS.

Same patterns. Same flow. TypeScript type safety on top.

PHP · Laravel
// app/Http/Controllers/UserController.php

class UserController extends Controller
{
    public function __construct(
        private readonly UserService $users,
    ) {}

    public function store(StoreUserRequest $request): JsonResponse
    {
        $user = $this->users->create($request->validated());
        event(new UserRegistered($user));

        return response()->json($user, 201);
    }
}
TypeScript · FaberJS
// app/controllers/UserController.ts

@Injectable()
export class UserController extends Controller {
  constructor(private users: UserService) {
    super()
  }

  async store(req: Request): Promise<Response> {
    const user = await this.users.create(req.validated())
    await event(new UserRegistered(user))

    return this.json(user, 201)
  }
}
Same constructor injection
Same validated() pattern
Same event() helper
Same response shape
The full stack

Every layer, one mental model.

Click through a real request — from route definition all the way down to the database model.

routes/api.ts
import { Route } from '@faber-js/router'
import { PostController } from '../app/controllers/PostController'

Route.group({ prefix: '/api', middleware: ['auth'] }, () => {
  Route.get('/posts',         [PostController, 'index'])
  Route.post('/posts',        [PostController, 'store'])
  Route.get('/posts/:id',     [PostController, 'show'])
  Route.put('/posts/:id',     [PostController, 'update'])
  Route.delete('/posts/:id',  [PostController, 'destroy'])
})
AI-native

Agents are infrastructure
now. Treat them like it.

DI, typed tool schemas, per-session memory, authorization, structured output, and SSE streaming. Built into the framework — not bolted on.

@faber-js/aiapp/agents/SupportAgent.ts
import { Agent, Tool, Authorize, t } from '@faber-js/ai'
import { Order } from '../models/Order'

export class SupportAgent extends Agent {
  override model = 'claude-sonnet-4-6'

  override output = t.object({
    summary:  t.string(),
    severity: t.enum(['low', 'medium', 'high']),
    nextStep: t.string().optional(),
  })

  @Tool({
    description: 'Look up an order by ID',
    input: { id: t.string() },
  })
  @Authorize('view-order', ([{ id }]) => id)
  async lookupOrder({ id }: { id: string }) {
    return Order.with('items', 'shipment').findOrFail(id)
  }

  @Tool({
    description: 'Refund an order — requires manager role',
    input: { id: t.string(), reason: t.string() },
  })
  @Authorize('refund-order', ([{ id }]) => id)
  async refund({ id, reason }) {
    return await this.refundService.process(id, reason)
  }
}
live SSE stream
Typed tools
Schemas, validation, authorization
Structured output
Type-safe responses by contract
SSE streaming
Token-by-token to the browser
Per-session memory
Conversation persistence built in
Batteries included

Everything you need.
Nothing you don't.

Every feature a production backend requires — shipped as first-class, independently versioned packages.

Expressive Routing

Route groups, resource routes, named routes, and model binding — fluent API, zero config.

Route.group({ prefix: '/api', middleware: ['auth'] }, () => {
  Route.resource('posts', PostController)
  Route.get('/me', [UserController, 'me'])
})

ActiveRecord ORM

Eloquent-style models with relationships, scopes, and an expressive query builder. SQLite, PostgreSQL, MySQL — swap drivers with one line.

const posts = await Post
  .where('published', true)
  .with('author', 'tags')
  .orderBy('created_at', 'desc')
  .paginate(20)

Queues & Jobs

BullMQ-backed queues with a one-liner dispatch API. Retry, delay, prioritise. Or use the sync driver — no Redis required for local dev.

await dispatch(new SendWelcomeEmail(user))

await dispatch(new ProcessPayment(order))
  .onQueue('payments')
  .delay(60)

Events & Listeners

Decouple your app with a typed event bus. Listeners can run synchronously or queued.

await event(new UserRegistered(user))

class SendWelcomeEmail {
  async handle(e: UserRegistered) {
    await Mail.to(e.user.email).send(new WelcomeMail())
  }
}

Auth & Policies

JWT guards, API tokens with scoped abilities, password reset, and resource policies — wired in automatically.

Route.group({ middleware: ['auth'] }, () => {
  Route.get('/dashboard', [DashController, 'index'])
})

const user = req.user<User>()
await this.authorize('update', post)

Artisan-style CLI

Generate controllers, models, jobs, mailables, agents, migrations and more from a single command.

npx faber make:model Post -m
npx faber make:agent SupportAgent
npx faber make:mail WelcomeMail
npx faber db:migrate
npx faber serve

Frontend Bridge

Build React or Vue SPAs using server-side routing — no separate API, no manual JSON wiring. End-to-end type safety.

return this.render('Users/Index', {
  users: await this.userService.all(),
})

const { props } = usePage<{ users: User[] }>()
<Link href="/users/create">Create</Link>

Real-Time Channels

WebSocket channels that feel like HTTP routes — public, private, presence — same DI, same auth, same shape.

Channel.presence('room.{slug}', [RoomChannel, 'join'])

async join(socket: Socket, slug: string) {
  socket.joinPresence(`room.${slug}`, { id, name })
  socket.on('msg', (m) => socket.broadcast(m))
}

Schema-First Models

One declaration drives your model, migrations, validation rules, factory, and OpenAPI spec — all type-inferred.

const User = schema('users', {
  id:    t.id(),
  name:  t.string().min(2).max(100),
  email: t.email().unique(),
  role:  t.enum(['admin','editor','viewer']),
})

DevTools Dashboard

Zero-config request, query, and event tracing. Live at /_faber in dev — disabled in production automatically.

app.register(new DevToolsServiceProvider(app, {
  db: getConnection(),
  dispatcher: eventDispatcher,
}))

// Open http://localhost:3000/_faber

Caching & Locks

Redis, memory, and database drivers with the same fluent API. Atomic locks and a built-in rate limiter.

await Cache.remember('users:active', 60, async () => {
  return User.where('active', true).get()
})

await Cache.lock('process-order:1234', 10).get(async () => {
  await processOrder(order)
})
Run anywhere

Same code.
Four runtimes.

Pick the runtime that fits your deployment. Swap any time — the rest of your app doesn't change.

Adapter for Node.jsdefault
// server.ts — production Node deployment
import { app } from './bootstrap/app'
import { createFastifyAdapter } from '@faber-js/adapters/fastify'

const adapter = createFastifyAdapter(app)
await adapter.listen({ port: 3000, host: '0.0.0.0' })
Meet your new Artisan

faber.
Your CLI superpower.

A full-featured CLI that generates anything your app needs. Modelled on Laravel's Artisan so every command feels familiar.

Generate
faber make:controller
faber make:model -m
faber make:service
faber make:job
faber make:event
faber make:listener
faber make:middleware
faber make:migration
faber make:provider
faber make:agent
faber make:mail
faber make:view
faber make:schema
faber make:channel
Database
faber db:migrate
faber db:rollback
faber db:fresh
faber db:refresh
faber db:seed
faber db:status
Dev
faber serve
faber tinker
faber route:list
faber key:generate
faber CLI
$ npx faber make:model Post -m
✔ Created app/models/Post.ts
✔ Created database/migrations/2026_create_posts_table.ts
 
$ npx faber make:agent SupportAgent
✔ Created app/agents/SupportAgent.ts
 
$ npx faber db:migrate
✔ Ran migration: 2026_create_users_table
✔ Ran migration: 2026_create_posts_table
2 migrations ran successfully.
 
$ npx faber route:list
 
GET /api/posts PostController@index
POST /api/posts PostController@store
GET /api/posts/:id PostController@show
PUT /api/posts/:id PostController@update
DELETE /api/posts/:id PostController@destroy
The ecosystem

Twenty-five packages.
One framework.

Every package is independently versioned and published under @faber-js. Install only what you need — or scaffold everything at once.

Core5
@faber-js/coreIoC, providers, facades
@faber-js/config.env + typed config
@faber-js/httpRequest, Response, middleware
@faber-js/routerRouting, groups, model binding
@faber-js/consoleCLI, generators, tinker
Data3
@faber-js/ormActiveRecord, migrations
@faber-js/schemaSchema-first models
@faber-js/validationRules engine, FormRequest
Async3
@faber-js/queueBullMQ jobs, sync driver
@faber-js/eventsTyped event/listener bus
@faber-js/channelsWebSockets, presence, broadcast
Auth & Security2
@faber-js/authJWT, API tokens, policies, password reset
@faber-js/cryptHash, AES-256-GCM, signed URLs
Communication2
@faber-js/mailMailable classes, SMTP, fakes
@faber-js/http-clientFluent fetch, retries, faking
AI-Native1
@faber-js/aiAgents, tools, streaming, structured output
Frontend4
@faber-js/bridgeBridge protocol + Vite plugin
@faber-js/bridge-reactusePage, useForm, Link
@faber-js/bridge-vueusePage, useForm, BridgeLink
@faber-js/viewJSX server-side views
Infrastructure5
@faber-js/cacheRedis, memory, DB, locks, rate limiter
@faber-js/devtoolsRequest, query, event tracing
@faber-js/adaptersFastify, Bun, Lambda, Cloudflare
@faber-js/supportCollection, Str, Arr, Pipeline
@faber-js/testingHTTP test client, DB assertions
Build something real

Start in 60 seconds.

One command. Conventions in place. Production-ready from day one.

$npm create faberjs@latest my-app