Framework Comparison

How tekir compares to Express, Elysia, Hono, AdonisJS, and Fastify across features, performance, and API shape.

Feature Comparison

A high-level overview of features across frameworks. Built-in means it ships with the framework core. Official means a separate package maintained by the framework team. - means not available or community-only.

FeaturetekirExpressElysiaHonoAdonisJSFastify
RuntimeBun / Node.jsNode.jsBun / Node.jsAnyNode.jsNode.js
TypeScriptNativeManualNativeNativeNativePlugin
ValidationAny (Zod)-TypeBoxBuilt-inVineJSJSON Schema
TestingOfficial---Japa-
Database/ORMOfficial---Lucid-
MongoDBOfficial-----
RedisOfficial---OfficialOfficial
DI ContainerBuilt-in---Built-in-
AuthOfficial---Official-
Social AuthOfficial---Official-
SessionOfficial---OfficialOfficial
MailOfficial---Official-
File StorageOfficial---Official-
CacheOfficial---OfficialOfficial
EventsOfficial---Built-in-
CronOfficial-Official-Official-
WebSocketOfficial-Built-inBuilt-in-Official
SwaggerOfficial-OfficialOfficial-Official
Rate LimitingOfficial---OfficialOfficial
i18nOfficial--Built-inOfficial-
CORSOfficial-OfficialBuilt-inBuilt-inOfficial
Static FilesOfficialBuilt-inOfficial-Built-inOfficial
HashingOfficial---Built-in-
EncryptionOfficial---Built-in-
QueueOfficial-----
Health ChecksOfficial---Built-in-
Env ValidationOfficial---Built-in-
FrontendVite / Next.js / Bun---Inertia-
ConfigOfficial---Built-inOfficial
Body ParserBuilt-inBuilt-inBuilt-inBuilt-inBuilt-inBuilt-in
Single ExeYes-Yes---

Code Comparison

The same endpoint written in each framework, side by side.

Hello World

A minimal HTTP server returning JSON.

import { tekir } from '@tekir/core'

const { router, start } = await tekir({
  config: { app: { port: 3000 } }
})

router.get('/', () => ({ message: 'Hello World' }))

start()

CRUD Endpoint

A full CRUD API with database and validation in a single file. In tekir, database access, body parsing, and Zod-based validation come from first-party packages.

import { tekir } from '@tekir/core'
import { DatabaseProvider } from '@tekir/db'
import { bodyParser } from '@tekir/bodyparser'
import type { Database } from '@tekir/db'
import { z } from 'zod'

const { router, service, start } = await tekir({
  config: {
    app: { port: 3000 },
    database: {
      default: 'sqlite',
      connections: { sqlite: { driver: 'sqlite', connection: { path: ':memory:' } } }
    }
  },
  providers: [DatabaseProvider],
  routerMiddleware: [bodyParser()]
})

const db = service<Database>('db')
await db.exec('CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, done INTEGER DEFAULT 0)')

const schema = z.object({ title: z.string().min(1), done: z.boolean().default(false) })

router.get('/api/todos', async () => await db.query('SELECT * FROM todos'))

router.post('/api/todos', async ({ body, response }) => {
  const data = schema.parse(body)
  await db.run('INSERT INTO todos (title, done) VALUES (?, ?)', [data.title, data.done ? 1 : 0])
  return response.created(await db.queryOne('SELECT * FROM todos ORDER BY id DESC LIMIT 1'))
})

router.put('/api/todos/:id', async ({ params, body, response }) => {
  await db.run('UPDATE todos SET title = ?, done = ? WHERE id = ?', [body.title, body.done ? 1 : 0, params.id])
  return response.ok(await db.queryOne('SELECT * FROM todos WHERE id = ?', [params.id]))
})

router.delete('/api/todos/:id', async ({ params, response }) => {
  await db.run('DELETE FROM todos WHERE id = ?', [params.id])
  return response.noContent()
})

start()

Performance

tekir and Elysia perform within 1% of each other on average across all endpoints. Both sit at near-raw Bun.serve() performance.

EndpointRaw BuntekirElysiaDiff
/json16,30316,29216,338-0.3%
/users/4216,56116,31216,180+0.8%
/posts/1/comments/516,34316,29516,009+1.8%
/search?q=hello&page=216,02816,06915,718+2.2%
AVERAGE16,24316,16916,115+0.3%

Measured with autocannon: 100 connections, 10x pipelining, 10-second window.

Detailed Comparisons

For in-depth, side-by-side code comparisons with specific frameworks: