Skip to main content

Guide

Encore.ts vs Hono vs Elysia (2026)

Compare Encore.ts, Hono, and Elysia for type-safe backend starters in 2026: runtime fit, API contracts, deployment model, starter ecosystem, and SaaS tradeoffs.

StarterPick Team
Hero image for Encore.ts vs Hono vs Elysia (2026)

TL;DR

Hono is the safest default for a type-safe backend starter when you still want runtime choice: its official docs position it as a small Web Standards framework that runs on Cloudflare Workers, Fastly, Deno, Bun, Vercel, Netlify, AWS Lambda, Lambda@Edge, and Node.js. Elysia is the strongest Bun-native pick when end-to-end type inference through Eden Treaty matters more than portability. Encore.ts is not just another router; choose it when you want the backend framework, service graph, local infrastructure, deployment workflow, and generated clients to come from one opinionated platform.

Key Takeaways

  • Hono is the flexible starter choice for edge APIs, serverless APIs, and teams that may move between Workers, Bun, Node, Lambda, or Vercel later.
  • Elysia is best when the starter is deliberately Bun-first and the API/client contract should flow from the app definition through Eden Treaty.
  • Encore.ts is the platform choice for teams that want type-safe APIs plus integrated infrastructure, service catalog, local dev, observability, and deployment flows.
  • Performance claims should be treated as workload-specific. Elysia and Bun are marketed around speed, Hono is tiny and fast across runtimes, and Encore optimizes for platform leverage rather than raw router benchmarks.
  • Starter ecosystem depth still favors Hono. Elysia has a smaller but active Bun ecosystem, while Encore fits best when the official examples and platform workflow match your architecture.
  • Best pairing: Hono + Cloudflare/D1 for edge SaaS APIs, Elysia + Bun for performance-oriented internal/product APIs, Encore.ts for cloud-native service backends where managed infrastructure is the main pain.

What Changed in This Refresh

  • Re-centered the guide around the GSC intent: "type-safe backend starters" rather than generic JavaScript framework benchmarks.
  • Replaced exact star-count and benchmark shorthand with source-backed, conservative claims from the official Encore.ts, Hono, Elysia, Eden Treaty, and Bun docs checked in May 2026.
  • Added clearer decision rules for Next.js SaaS teams choosing between a Hono API service, a Bun/Elysia service, and an Encore-managed backend.
  • Updated internal links toward adjacent StarterPick guides on serverless boilerplates, tRPC/oRPC/ts-rest, T3 Stack, and Next.js SaaS stack decisions.

The Three Frameworks

HonoElysiaEncore.ts
Runtime fitWeb Standards across Workers, Deno, Bun, Node, serverless, and edge hostsBun-first, with growing integrations around Bun-native appsEncore runtime/platform workflow for TypeScript services
PhilosophySmall, composable HTTP frameworkErgonomic app definition with schema-driven typesBackend platform: APIs, infra primitives, service graph, local dev, deploys
E2E typesHono RPC client, OpenAPI/Zod packages, or explicit shared schemasEden Treaty derives client types from the Elysia appGenerated TypeScript clients from Encore API definitions
Starter ecosystemBroadest starter/community surface of the threeSmaller but active Bun-first starter surfaceMost useful when official examples/platform flow fit
Best forEdge APIs and portable SaaS servicesBun API servers and internal product APIsCloud-native service backends with infrastructure pain
DeploymentWorkers, Bun, Deno, Node, serverless, Vercel/Netlify, Lambda, moreBun servers and integrations that support Elysia/BunEncore Cloud, self-hosting, and supported deployment/export flows

Hono — The Multi-Runtime Champion

Founded: 2022 | Creator: Yusuke Wada | Official docs checked: May 2026

Hono started as a Cloudflare Workers framework and evolved into a Web Standards framework that runs on many JavaScript runtimes. The API surface is Express-like but modernized with TypeScript-first design, middleware composition, and a small core.

Why SaaS Teams Choose Hono

import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";
import { z } from "zod";

const app = new Hono();

// Type-safe request validation
const createProjectSchema = z.object({
  name: z.string().min(1).max(100),
  slug: z.string().regex(/^[a-z0-9-]+$/),
});

app.post(
  "/projects",
  zValidator("json", createProjectSchema),
  async (c) => {
    const { name, slug } = c.req.valid("json"); // typed!
    const project = await db.insert(projects).values({ name, slug, userId: c.var.userId });
    return c.json(project, 201);
  }
);

// RPC — call from client with full types
// Using hono/client
import type { AppType } from "./server";
import { hc } from "hono/client";

const client = hc<AppType>("http://localhost:3000");
const res = await client.projects.$post({ json: { name: "My SaaS", slug: "my-saas" } });

Hono SaaS Starters

# Cloudflare Workers (most popular)
npm create cloudflare@latest my-api -- --type=hono

# Bun
bun create hono my-api --template bun

# Node.js
npm create hono my-api -- --template nodejs

# Vercel
npm create hono my-api -- --template vercel

Community SaaS starters:

  • hono-saas-starter — Workers + D1 + Clerk + Stripe
  • hono-drizzle-starter — Bun + Hono + Drizzle + Postgres
  • Multiple "hono + shadcn" full-stack starters on GitHub

Hono Strengths

  • ✅ Deploy anywhere — migrate from Workers to Bun to Lambda without rewriting
  • ✅ Large middleware ecosystem (@hono/zod-validator, @hono/clerk-auth, @hono/cors)
  • ✅ Most SaaS starters of the three
  • ✅ Excellent documentation

Hono Weaknesses

  • ❌ No built-in database abstraction
  • ❌ Type inference requires RPC client setup (not automatic like Elysia's Eden)
  • ❌ File-based routing requires a plugin

Elysia — Bun-Native Performance

Founded: 2023 | Creator: SaltyAom | Official docs checked: May 2026

Elysia is built around Bun and TypeScript-first ergonomics. Its homepage describes it as a backend TypeScript framework with end-to-end type safety, strong speed, and developer experience across runtimes, supercharged by Bun. Eden Treaty is the key starter advantage: your client contract can be inferred from the Elysia app instead of maintained as a parallel schema.

Elysia's Eden Treaty

// server.ts
import { Elysia, t } from "elysia";

const app = new Elysia()
  .get("/", "Hello Elysia")
  .post(
    "/projects",
    ({ body }) => {
      // body is typed from the schema!
      return db.insert(projects).values(body);
    },
    {
      body: t.Object({
        name: t.String({ minLength: 1 }),
        slug: t.String({ pattern: "^[a-z0-9-]+$" }),
      }),
    }
  )
  .listen(3000);

export type App = typeof app;

// client.ts — zero config, full types
import { treaty } from "@elysiajs/eden";
import type { App } from "./server";

const client = treaty<App>("http://localhost:3000");

// Fully typed — no separate schema file or type generation step
const { data, error } = await client.projects.post({
  name: "My SaaS",
  slug: "my-saas",
});

Eden Treaty is the standout feature. Unlike tRPC (which requires a separate router/procedure definition) or Hono RPC (which requires hc() client), Eden Types flow automatically from your Elysia app definition.

Elysia with Bun's Built-In Features

import { Elysia } from "elysia";
import { Database } from "bun:sqlite"; // Bun built-in SQLite

const db = new Database("myapp.db");
db.run(`CREATE TABLE IF NOT EXISTS users (
  id TEXT PRIMARY KEY,
  email TEXT UNIQUE,
  created_at INTEGER
)`);

const app = new Elysia()
  .get("/users/:id", ({ params }) => {
    return db.query("SELECT * FROM users WHERE id = ?").get(params.id);
  })
  .listen(3000);

Elysia SaaS Starters

The ecosystem is growing but smaller than Hono:

# Official starter
bun create elysia my-app

# Community starters
bunx degit saltyaom/elysia-bun-example my-app
bunx degit elysiajs/elysia-with-prisma my-app

Notable: elysia-saas-starter (community) — Bun + Elysia + Drizzle + Clerk + Stripe.

Elysia Strengths

  • ✅ Bun-native performance and DX for teams already standardizing on Bun
  • ✅ Eden Treaty: excellent end-to-end type safety DX
  • ✅ Plugin system with lifecycle hooks
  • ✅ Swagger/OpenAPI generation via official plugin patterns

Elysia Weaknesses

  • ❌ Bun-first posture narrows your hosting and team-runtime choices
  • ❌ Smaller ecosystem and fewer SaaS starters than Hono
  • ❌ Less proven than Hono for teams that need broad multi-runtime portability

Encore.ts — Infrastructure as TypeScript

Founded: 2021 | Creator: Encore team | Official docs checked: May 2026

Encore.ts takes a fundamentally different approach. Instead of being only an HTTP framework, it is a backend development platform for TypeScript services. You define APIs and infrastructure primitives in code, then use Encore's local development, service catalog, observability, deployment, and generated-client workflow around that app model.

// No express, no hono, no routing — just Encore annotations
import { api, APIError } from "encore.dev/api";
import { SQLDatabase } from "encore.dev/storage/sqldb";

// Encore generates a PostgreSQL database
const db = new SQLDatabase("saas", {
  migrations: "./migrations",
});

// This becomes an HTTP endpoint
export const getProject = api(
  { expose: true, method: "GET", path: "/projects/:id" },
  async ({ id }: { id: string }) => {
    const project = await db.queryRow`
      SELECT * FROM projects WHERE id = ${id}
    `;
    if (!project) throw APIError.notFound("Project not found");
    return { project };
  }
);

// This becomes a Pub/Sub publisher
import { Topic } from "encore.dev/pubsub";

export const ProjectCreated = new Topic<{ projectId: string; userId: string }>(
  "project-created",
  { deliveryGuarantee: "at-least-once" }
);

// This becomes a subscriber
import { Subscription } from "encore.dev/pubsub";

export const sendWelcomeEmail = new Subscription(ProjectCreated, "send-welcome-email", {
  handler: async (event) => {
    await resend.emails.send({
      to: await getUserEmail(event.userId),
      subject: "Welcome to the project",
      html: `<p>Your project ${event.projectId} is ready.</p>`,
    });
  },
});

Encore's leverage: this TypeScript code becomes part of a backend app graph that Encore can understand. Depending on how you deploy, Encore can provide or generate the surrounding service metadata, local infrastructure, API clients, observability, and deployment artifacts so the team writes far less glue code around the backend.

Encore SaaS Starters

# Official Encore CLI
encore app create my-saas --example=user-auth

# Available examples
encore app create --example=slack-bot
encore app create --example=saas-starter
encore app create --example=stripe-checkout

Encore maintains official TypeScript example apps and documentation for common backend patterns. Treat those examples as the starter surface: if your SaaS shape matches Encore's app model, you get more platform leverage than you would from a thin template.

Encore Strengths

  • ✅ Less hand-written infrastructure and deployment glue
  • ✅ Service catalog, tracing, metrics, and logging are part of the platform workflow
  • ✅ Local development can run services and infrastructure-like dependencies together
  • ✅ Encore Cloud plus self-hosting/deployment docs give a clearer path than a generic framework alone
  • ✅ Type-safe APIs and generated clients fit multi-service backends

Encore Weaknesses

  • ❌ More platform lock-in than Hono or Elysia
  • ❌ Not the right fit when you specifically want Bun-native or Workers-first deployment
  • ❌ Smaller community starter surface than Hono or Elysia
  • ❌ Less flexible if you already have a mature custom infrastructure platform

Comparison: Same SaaS Feature in Three Frameworks

Let's implement a simple "create organization" endpoint:

Hono

app.post(
  "/organizations",
  zValidator("json", createOrgSchema),
  clerkMiddleware(),
  async (c) => {
    const { userId } = getAuth(c);
    const { name, slug } = c.req.valid("json");

    const org = await db.insert(organizations).values({ id: nanoid(), name, slug, ownerId: userId }).returning();
    return c.json(org[0], 201);
  }
);

Elysia

app.post(
  "/organizations",
  async ({ body, store: { userId } }) => {
    return db.insert(organizations).values({ id: nanoid(), ...body, ownerId: userId }).returning();
  },
  {
    body: t.Object({
      name: t.String({ minLength: 1 }),
      slug: t.String({ pattern: "^[a-z0-9-]+$" }),
    }),
    beforeHandle: [authenticate],
  }
);

Encore.ts

export const createOrganization = api(
  { expose: true, method: "POST", path: "/organizations", auth: true },
  async ({ name, slug }: { name: string; slug: string }) => {
    const userId = getAuthData()!.userID;
    const org = await db.queryRow`
      INSERT INTO organizations (id, name, slug, owner_id)
      VALUES (gen_random_uuid(), ${name}, ${slug}, ${userId})
      RETURNING *
    `;
    return { organization: org };
  }
);

Choosing Your Framework

You should chooseIf
HonoDeploying to Cloudflare Workers / edge; need multi-runtime flexibility; want the most starters
ElysiaUsing Bun; want best performance; love Eden Treaty's DX; building a pure API backend
Encore.tsWant a backend platform, service catalog, generated clients, and much less infrastructure glue

For a typical Next.js SaaS (API routes)

Stick with Next.js Route Handlers — none of these frameworks add value for a monolithic Next.js app with a few API routes.

For a dedicated API service

Hono if you want edge deployment, Elysia if you're on Bun, Encore if you want managed infrastructure.


Making the Final Decision: Real-World Scenarios

The comparison table is a starting point. Here's how the decision plays out in concrete scenarios:

Scenario 1: AI SaaS with a streaming chat endpoint. You need a dedicated backend service that handles LLM streaming, token metering, and user sessions. Hono is the safest default because it can run at the edge, has maintained middleware patterns for auth and validation, and keeps the deployment target portable. Elysia can work if the whole service is Bun-first, but Hono gives you more escape hatches.

Scenario 2: Internal developer tool with strict type contracts. Your team is Bun-first and the API is consumed only by an internal React dashboard. Elysia + Eden Treaty gives you the tightest end-to-end type safety — changes to the API surface immediately produce TypeScript errors on the client without any code generation step. The performance headroom on Bun means you'll never hit throughput limits at internal scale.

Scenario 3: Microservices for a B2B SaaS. You're splitting a monolith into five services: users, billing, notifications, analytics, and the core product API. Encore.ts is the compelling choice when you want the service graph, local infrastructure, generated clients, and deployment workflow to be part of the same platform instead of stitched together from separate libraries.

Migrating From Express

If you're on Express today, the move to Hono is the lowest-friction migration. Hono's middleware model mirrors Express: app.use() for middleware, app.get()/post() for routes, c.json() instead of res.json(). Most Express route handlers translate with minimal changes — the main adjustment is the context object and the different middleware signature. Expect a one-week migration for a medium-sized Express API.

Migrating to Elysia from Express requires a larger mental shift toward Elysia's declarative plugin and lifecycle hook system. It's a real rewrite, not a refactor, but the performance gain is worth it if you're committing to Bun.

Migrating to Encore.ts is an architectural shift, not just a framework swap. Budget 1-2 weeks even for a modest API.

Middleware Ecosystem Depth

Hono's @hono/ organization on npm contains official middleware for Zod validation, Clerk auth, JWT, CORS, rate limiting, and OpenAPI documentation generation. You're composing maintained packages, not writing middleware from scratch.

Elysia's ecosystem is built around plugins (@elysiajs/cors, @elysiajs/jwt, @elysiajs/static), but the community ecosystem is smaller than Hono's. For niche requirements you'll write more code yourself.

Encore.ts doesn't have a traditional middleware ecosystem because infrastructure concerns are handled by the Encore platform rather than npm packages. This is a feature — you don't need rate-limiting middleware when Encore's platform handles it — but it means you're more dependent on Encore's opinionated approach.

What These Frameworks Have in Common

Despite their different philosophies, Hono, Elysia, and Encore share several properties that matter for SaaS in 2026:

All three are TypeScript-first and reduce API contract drift compared with an untyped Express-style backend. All three can document or generate API contracts, but through different seams: Hono usually uses explicit RPC/OpenAPI helpers, Elysia derives more from the app/schema definition, and Encore generates clients/docs from the platform's API model. The real decision is not "which router is fastest?" It is which interface your team wants to maintain: portable HTTP framework, Bun-native app definition, or managed backend platform.

For adjacent StarterPick research, pair this guide with the tRPC v11 vs oRPC vs ts-rest guide, the T3 Stack review, and the Next.js SaaS tech stack guide. For Hono in a serverless context, the best serverless boilerplates guide covers Hono on Cloudflare Workers alongside SST and Vercel Functions.

Testing Strategies for Each Framework

Testing a backend API is where framework philosophy shows up in practice. The three frameworks require meaningfully different testing approaches.

Hono apps test cleanly with the built-in test utilities:

import { testClient } from 'hono/testing'
import { app } from './app'

describe('POST /projects', () => {
  it('creates a project', async () => {
    const client = testClient(app)
    const res = await client.projects.$post({
      json: { name: 'Test Project', slug: 'test-project' }
    })
    expect(res.status).toBe(201)
    const data = await res.json()
    expect(data.name).toBe('Test Project')
  })
})

The testClient from hono/testing wraps your app and returns a typed client — the same RPC client you'd use from the frontend. Test request/response contracts with full type inference.

Elysia apps use a similar pattern with Eden Treaty on the test client:

import { treaty } from '@elysiajs/eden'
import { app } from './app'

const api = treaty(app)

describe('projects', () => {
  it('creates a project', async () => {
    const { data, error } = await api.projects.post({
      name: 'Test Project',
      slug: 'test-project'
    })
    expect(error).toBeNull()
    expect(data?.name).toBe('Test Project')
  })
})

Elysia's Eden Treaty provides end-to-end type safety in tests without any separate type generation step — the same advantage it provides in application code.

Encore.ts testing runs against the Encore test runner, which starts a local version of your infrastructure:

encore test ./...   # Run all tests with local Encore infrastructure

Each test runs with access to real (local) database instances, pub/sub, and secrets — Encore injects the infrastructure context automatically. This is more realistic than mocked dependencies but requires the Encore runtime to be installed.

Authentication Patterns Across All Three

Authentication is a SaaS requirement, not an optional feature. Here's how auth integrates across the three frameworks:

Hono + Clerk is the most common enterprise pattern for Next.js + Hono backends:

import { clerkMiddleware, getAuth } from '@hono/clerk-auth'

app.use('*', clerkMiddleware())

app.get('/api/me', (c) => {
  const auth = getAuth(c)
  if (!auth?.userId) return c.json({ error: 'Unauthorized' }, 401)
  return c.json({ userId: auth.userId })
})

The @hono/clerk-auth middleware validates Clerk's JWT on every request. The getAuth() call extracts the session inside route handlers. Because Hono runs on Cloudflare Workers, this pattern supports edge auth validation with global latency.

Elysia uses a plugin/lifecycle approach for auth:

const authPlugin = new Elysia({ name: 'auth' })
  .derive(async ({ headers }) => {
    const token = headers['authorization']?.replace('Bearer ', '')
    const payload = await verifyJWT(token)
    return { user: payload }
  })
  .macro(({ onBeforeHandle }) => ({
    requireAuth(value: boolean) {
      if (value) onBeforeHandle(({ user, error }) => {
        if (!user) return error(401, 'Unauthorized')
      })
    }
  }))

app.use(authPlugin).get('/api/me', ({ user }) => user, { requireAuth: true })

Encore.ts auth is declared at the API level using an auth handler:

import { authHandler } from 'encore.dev/auth'

export const myAuthHandler = authHandler(
  { expose: true, method: 'GET', path: '/auth' },
  async (params: HandlerParams): Promise<AuthData> => {
    const token = params.headers['authorization']
    return validateToken(token) // returns { userID, roles }
  }
)

Once the auth handler is defined, any endpoint marked auth: true automatically validates the JWT and makes user data available via getAuthData().


Methodology

  • Refreshed official source checks in May 2026 against Encore.ts TypeScript docs, Hono docs, Hono RPC docs, Elysia homepage/docs, Elysia Eden docs, and Bun docs.
  • Treated framework benchmark claims as directional only; this guide prioritizes starter architecture, runtime fit, type contracts, deployment posture, and ecosystem depth.
  • Checked internal StarterPick guide inventory for adjacent type-safe RPC, serverless boilerplate, T3 Stack, and Next.js SaaS stack links.
  • Preserved the existing canonical URL and indexable guide route rather than creating a competing page.

Find all Hono, Elysia, and Encore starters on StarterPick — filter by framework, runtime, and features.

For broader context on boilerplate and framework selection, see the top SaaS boilerplates guide and the Next.js SaaS tech stack guide.

Evaluating whether to use a boilerplate at all? The best free open-source SaaS boilerplates guide covers open-source starters that pair well with these backend frameworks.

OpenAPI and Documentation Generation

API documentation is a selling point for developer-facing SaaS. All three frameworks support OpenAPI generation, but the ergonomics differ.

Hono uses @hono/zod-openapi — a Zod-first approach where you define routes with explicit input/output schemas and the OpenAPI spec is generated automatically:

import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
import { z } from 'zod'

const app = new OpenAPIHono()

const ProjectSchema = z.object({
  id: z.string(),
  name: z.string(),
})

const createProjectRoute = createRoute({
  method: 'post',
  path: '/projects',
  request: { body: { content: { 'application/json': { schema: ProjectSchema.omit({ id: true }) } } } },
  responses: { 201: { content: { 'application/json': { schema: ProjectSchema } }, description: 'Created' } },
})

app.openapi(createProjectRoute, async (c) => {
  const body = c.req.valid('json')
  // ...
  return c.json(newProject, 201)
})

app.doc('/openapi.json', { openapi: '3.0.0', info: { title: 'My API', version: '1.0.0' } })

Elysia includes Swagger UI generation via the @elysiajs/swagger plugin — no extra schema definitions needed, since Elysia's TypeBox schemas generate both validation and documentation:

import { Elysia } from 'elysia'
import { swagger } from '@elysiajs/swagger'

const app = new Elysia()
  .use(swagger())  // Adds /swagger UI and /swagger/json
  .post('/projects', ({ body }) => createProject(body), {
    body: t.Object({ name: t.String(), slug: t.String() }),
    response: t.Object({ id: t.String(), name: t.String() })
  })

Encore.ts generates OpenAPI documentation automatically from endpoint definitions — no extra packages or decorators needed. The encore gen client command produces a TypeScript client from the OpenAPI spec for use in frontend applications. For microservices architectures where services need to call each other, the generated client with full types eliminates a class of integration bugs.

For teams building public APIs or developer tools as part of their SaaS, Encore's automatic documentation story is compelling. For internal APIs, Elysia's Swagger plugin path is ergonomic. Hono's @hono/zod-openapi offers the most control at the cost of explicit schema definitions per route.

Source Notes

Official pages checked for this refresh:

  • Encore.ts TypeScript docs: https://encore.dev/docs/ts
  • Hono docs: https://hono.dev/docs
  • Hono RPC docs: https://hono.dev/docs/guides/rpc
  • Elysia homepage/docs: https://elysiajs.com/
  • Elysia Eden docs: https://elysiajs.com/eden/overview
  • Bun docs: https://bun.sh/docs

The older Elysia essential/overview.html URL returned 404 during source probing, so this refresh uses the live Elysia homepage and Eden docs instead. Exact GitHub star counts and generic benchmark rankings were intentionally removed because they age quickly and are less useful than the runtime, type-contract, and deployment tradeoffs for starter selection.

The SaaS Boilerplate Matrix (Free PDF)

20+ SaaS starters compared: pricing, tech stack, auth, payments, and what you actually ship with. Updated monthly. Used by 150+ founders.

Join 150+ SaaS founders. Unsubscribe in one click.