Build Full-StackDeveloper Beta
Libraries
Build framework-agnostic libraries that embed backend and frontend logic in your users' applications
Libraries
Traditional libraries target either the frontend or backend.
Fragno Fragments
With Fragno, you build libraries as a full-stack package: Fragments.
Application
Developers use Fragments to quickly build full-fledged applications in their framework of choice.
Frameworks
These frameworks and more are already supported
With Fragno you build
Full-Stack Libraries
Traditional libraries integrate on either the frontend or the backend, and the user is responsible for the glue-code.
A Fragment does both, it's a full-stack library. Users integrate with only a couple lines of code. No glue.
10x the developer experience.
Define your API routes with full type safety. Routes are embedded directly in your user's application.
import { defineRoute } from "@fragno-dev/core";import { z } from "zod";export const route = defineRoute({ method: "POST", path: "/ai-chat", inputSchema: z.string(), outputSchema: z.array(/* ... */), handler: async ({ input }, { jsonStream }) => { const message = await input.valid(); const eventStream = await openai.responses.create({ /* ... */ }); return jsonStream(async (stream) => { // ... await stream.write( /* ... */ ); }); },});Embed Routes
HTTP Routes with automatic frontend bindings
State Management
Reactive client-side stores with invalidation built in
Streaming Support
Real-time newline-delimited JSON streaming
Middleware Support
Users can intercept and process requests before they reach your handlers
Agnostic Data Persistence
Define schemas, query with type safety, and write directly to the user's database
Define Your Schema
Type-safe tables with automatic migrations and support for indexes & relations
import { schema, idColumn, column } from "@fragno-dev/db/schema";export const commentSchema = schema((s) => { return s .addTable("comment", (t) => { return t .addColumn("id", idColumn()) .addColumn("content", column("string")) .addColumn("userId", column("string")) .addColumn("postId", column("string")) .addColumn( "createdAt", column("timestamp") .defaultTo((b) => b.now()) ) .createIndex("idx_post", ["postId"]); }) .addTable("user", (t) => { return t .addColumn("id", idColumn()) .addColumn("name", column("string")); }) .addReference("author", { type: "one", from: { table: "comment", column: "userId" }, to: { table: "user", column: "id" } });});Query with Type Safety
Joins, filtering, and cursor-based pagination
// Find comments with author dataconst comments = await orm.find( "comment", (b) => b .whereIndex("idx_post", (eb) => eb("postId", "=", postId) ) .orderByIndex("idx_created", "desc") .join((j) => j.author((authorBuilder) => authorBuilder.select(["name"]) ) ) .pageSize(20));// Fully typed resultsfor (const comment of comments) { console.log(comment.content); console.log(comment.author?.name); // ^? { name: string } | null}Atomic Transactions
Optimistic concurrency control with version checking
const uow = orm.createUnitOfWork();// Phase 1: Retrieve with version infouow.find("user", (b) => b.whereIndex("primary", (eb) => eb("id", "=", userId) ));const [users] = await uow.executeRetrieve();// Phase 2: Update with optimistic lockconst user = users[0];uow.update("user", user.id, (b) => b .set({ balance: user.balance + 100 }) .check() // Fails if version changed);const { success } = await uow.executeMutations();if (!success) { // Concurrent modification detected console.error("Retry transaction");}Test Everything
In-memory database for fast tests
import { createDatabaseFragmentForTest } from "@fragno-dev/test";describe("auth fragment", async () => { const { fragment, test } = await createDatabaseFragmentForTest( authFragmentDefinition, { adapter: { type: "drizzle-sqlite" } } ); afterAll(async () => { await test.cleanup(); }); it("creates user and session", async () => { const response = await fragment.handler( signUpRoute, { body: { email: "test@test.com", password: "password" } } ); expect(response.data).toMatchObject({ sessionId: expect.any(String), userId: expect.any(String) }); });});Documentation
Choose your path depending on whether you're a user or a library author
Introduction to Fragno
Understand the philosophy and vision behind Fragno. Learn why we think a framework-agnostic approach to building full-stack libraries is a great choice.
Read Introduction