Installation
Get a new tekir project up and running in under a minute.
Prerequisites
tekir requires Bun 1.3.10 or higher. It also runs on Node.js 22+ via @tekir/runtime, but Bun is the recommended runtime. If you haven't installed Bun yet:
# macOS / Linux
curl -fsSL https://bun.sh/install | bash
# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"Verify your Bun version:
bun --versionCreate a New Project
Use the official tekir CLI to scaffold a new project. The CLI will prompt you for a few options (database driver, auth strategy, frontend type, etc.) and then generate a fully configured project.
bunx create-tekir-app my-apptekir v0.1.0, creating project...
✓ Scaffolding project structure
✓ Writing configuration files
✓ Installing dependencies
Done! To get started:
cd my-app
bun run devAlternatively, you can install the packages manually if you want to add tekir to an existing Bun project:
bun add @tekir/core @tekir/http-decorators @tekir/config @tekir/loggerProject Templates
The CLI ships with 5 starter templates. Pass --template to skip the interactive prompt:
Minimal
Single-file TODO API with SQLite, Swagger, and CORS. Perfect for prototyping or learning tekir.
bunx create-tekir-app my-app --template=minimalAPI
Full API project with auth, database, validation, mail, and more. The recommended starting point for backend services.
bunx create-tekir-app my-app --template=apiFullstack
API + React frontend with views, auth, and database. Everything you need for a full-stack web application.
bunx create-tekir-app my-app --template=fullstackVite + React
tekir API backend + Vite React frontend served on the same port. Full HMR in development, optimized build in production.
bunx create-tekir-app my-app --template=with-viteNext.js
tekir API backend + Next.js SSR frontend on the same port. Pages router with API passthrough to tekir.
bunx create-tekir-app my-app --template=with-nextProject Structure
A freshly scaffolded tekir project has the following layout:
my-app/
├── index.ts # Entry point: tekir()
├── services.ts # Typed service accessors
├── types.ts # Module augmentation
├── env.ts # Environment validation
├── config/
│ ├── app.ts # Application config
│ ├── database.ts # Database config
│ ├── auth.ts # Auth config
│ ├── cache.ts # Cache config
│ └── ... # Other package configs
├── start/
│ ├── kernel.ts # Providers, middleware
│ ├── boot.ts # DB setup, cron registration
│ ├── events.ts # Event listeners
│ └── routes.ts # Route/controller registration
├── core/
│ ├── controllers/ # HTTP controllers
│ ├── models/ # Database models
│ ├── middleware/ # Custom middleware
│ ├── listeners/ # Event listeners
│ ├── schedules/ # Cron schedules
│ └── jobs/ # Background jobs
├── database/
│ ├── migrations/ # Database migrations
│ └── seeders/ # Database seeders
└── tests/ # Test filescore/
The core/ directory contains your application code, controllers, models, middleware, listeners, schedules, and jobs. This is where you will spend most of your time.
config/
All framework configuration lives here. Each file exports a typed configuration object using tekir's config utilities. You never have to parse environment variables manually; use env.ts for that.
start/
The start/ directory is the application bootstrap layer. Files are auto-loaded in order: kernel.ts first, boot.ts second, then remaining files alphabetically, and routes.ts last. Each file exports a default function that receives the TekirApp instance.
index.ts
The entry point for your application. It calls tekir() which returns a TekirApp with app, server, router, logger, config, service, start, onStart, and onShutdown:
import { tekir } from '@tekir/core'
const app = await tekir({
envFile: 'env.ts',
configDir: 'config',
startDir: 'start',
})
app.start()Environment Variables
tekir uses @tekir/env for type-safe environment variables. Your .env file looks like:
TZ=UTC
PORT=3000
HOST=0.0.0.0
LOG_LEVEL=info
APP_KEY= # run: tekir generate:key
# Database
DB_CONNECTION=sqlite
DB_FILE=./database/app.sqlite
# Or with PostgreSQL
# DB_CONNECTION=pg
# DB_HOST=localhost
# DB_PORT=5432
# DB_USER=postgres
# DB_PASSWORD=secret
# DB_DATABASE=myappAnd env.ts validates and types those values at startup:
import { defineEnv, str, port } from '@tekir/env'
export default defineEnv({
TZ: str({ default: 'UTC' }),
PORT: port({ default: 3000 }),
APP_KEY: str(),
DB_CONNECTION: str({ choices: ['sqlite', 'pg', 'mysql'] }),
DB_FILE: str({ default: '' })
})If a required variable is missing or has the wrong type, tekir will throw a descriptive error at boot time, never at request time.
Running the Server
Development
The dev server uses Bun's native file watcher for instant hot-reload:
# Start the development server with hot reload
tekir serve --dev
# Server started on http://localhost:3000Production
Build a plain bundle with --outdir, or a single self-contained executable with --compile. Compiled binaries dispatch commands directly: ./server routes, ./server generate:key. The tekir bin is only needed during development.
# Plain bundle
tekir build --outdir ./dist
# Single executable
tekir build --compile --outfile server
# Run the production binary
./server
# Or in source mode:
tekir serveEntry File Resolution
tekir figures out which file to import for every command using a fixed lookup order. In a default project layout you never type the entry path.
--entry <path>flag, accepted by every command. Use it when you have a one-off run from a custom file."tekir": { "entry": "<path>" }inpackage.json. Set this once if your entry is not one of the defaults; every command picks it up automatically.- First match among
index.ts,api/index.ts,app/index.ts,src/index.ts,index.js. The bin never treats a positional argument as an entry, so command arguments liketekir make:controller Userare passed through verbatim.
# tekir resolves the entry file in this order:
# 1. --entry <path> flag, anywhere in argv
# 2. "tekir": { "entry": "<path>" } in package.json
# 3. First match among these defaults:
# index.ts, api/index.ts, app/index.ts, src/index.ts, index.js
#
# 99% of projects keep the default and never specify an entry.
# Set "tekir.entry" once if you renamed the file:
# package.json
{
"name": "my-app",
"tekir": { "entry": "server.ts" }
}
# Then everything else stays clean:
tekir serve
tekir build --outdir ./dist
tekir routesEditor Setup
tekir is fully typed and works best with Visual Studio Code or any editor with TypeScript LSP support.
- Install the official TypeScript extension for VS Code.
- Enable
"typescript.tsdk": "node_modules/typescript/lib"in your workspace settings to use the project's TypeScript version. - Decorators require
"experimentalDecorators": trueand"emitDecoratorMetadata": truein yourtsconfig.json. The scaffolded project includes these by default.