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.
| Feature | tekir | Express | Elysia | Hono | AdonisJS | Fastify |
|---|---|---|---|---|---|---|
| Runtime | Bun / Node.js | Node.js | Bun / Node.js | Any | Node.js | Node.js |
| TypeScript | Native | Manual | Native | Native | Native | Plugin |
| Validation | Any (Zod) | - | TypeBox | Built-in | VineJS | JSON Schema |
| Testing | Official | - | - | - | Japa | - |
| Database/ORM | Official | - | - | - | Lucid | - |
| MongoDB | Official | - | - | - | - | - |
| Redis | Official | - | - | - | Official | Official |
| DI Container | Built-in | - | - | - | Built-in | - |
| Auth | Official | - | - | - | Official | - |
| Social Auth | Official | - | - | - | Official | - |
| Session | Official | - | - | - | Official | Official |
| Official | - | - | - | Official | - | |
| File Storage | Official | - | - | - | Official | - |
| Cache | Official | - | - | - | Official | Official |
| Events | Official | - | - | - | Built-in | - |
| Cron | Official | - | Official | - | Official | - |
| WebSocket | Official | - | Built-in | Built-in | - | Official |
| Swagger | Official | - | Official | Official | - | Official |
| Rate Limiting | Official | - | - | - | Official | Official |
| i18n | Official | - | - | Built-in | Official | - |
| CORS | Official | - | Official | Built-in | Built-in | Official |
| Static Files | Official | Built-in | Official | - | Built-in | Official |
| Hashing | Official | - | - | - | Built-in | - |
| Encryption | Official | - | - | - | Built-in | - |
| Queue | Official | - | - | - | - | - |
| Health Checks | Official | - | - | - | Built-in | - |
| Env Validation | Official | - | - | - | Built-in | - |
| Frontend | Vite / Next.js / Bun | - | - | - | Inertia | - |
| Config | Official | - | - | - | Built-in | Official |
| Body Parser | Built-in | Built-in | Built-in | Built-in | Built-in | Built-in |
| Single Exe | Yes | - | 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.
| Endpoint | Raw Bun | tekir | Elysia | Diff |
|---|---|---|---|---|
| /json | 16,303 | 16,292 | 16,338 | -0.3% |
| /users/42 | 16,561 | 16,312 | 16,180 | +0.8% |
| /posts/1/comments/5 | 16,343 | 16,295 | 16,009 | +1.8% |
| /search?q=hello&page=2 | 16,028 | 16,069 | 15,718 | +2.2% |
| AVERAGE | 16,243 | 16,169 | 16,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: