Performance
Tyravel ships snappy defaults for production: route caches, JSON fast paths, request pooling, compiled view LRU, and pool warm-up. This guide is the boot checklist and tuning reference for Tier 19 speed work.
Production boot checklist
Run these once per deploy (or in your CI image build):
tyravel config:cache
tyravel route:cache
tyravel view:cacheThen boot with production env:
NODE_ENV=production APP_DEBUG=false tyravel startIn your app entrypoint, call prepareHttpServer() after app.boot() so route and middleware caches are validated before accepting traffic.
What warms automatically
| Feature | Config / env | Default in production |
|---|---|---|
| Route cache | storage/framework/routes.json | Built by route:cache |
| Config cache | storage/framework/config.json | Built by config:cache |
| View compiled cache | view:cache + preloadCompiled: true | On in config/views.ts scaffold |
| DB pool warm-up | DB_POOL_WARMUP=true | On when NODE_ENV=production |
| Request pooling | http.requestPooling | On when APP_DEBUG=false |
| JSON fast path | http.jsonFastPath | On |
| Early 404 | http.early404 | On when APP_DEBUG=false |
Headless API mode
For JSON-only backends, use tyravel new --headless. Headless scaffolds skip views, SSR, and Echo — smaller boot profile and faster cold start. See Headless API.
HTTP hot path
- JSON fast path — stateless API routes skip session, CSRF, and view middleware. Tag routes with
withMiddlewareMeta(..., { tag: 'session' })only when you need sessions. - Request pooling — reuses
TyravelRequestinstances under load. Enable withrequestPooling: trueinconfig/http.ts(default off in debug, on in production scaffolds). - Keep-alive — Node adapter sets
keepAliveTimeout/headersTimeoutfor reverse-proxy deployments.
Views & SSR
view:cache— compile all.tyrtemplates to disk; production rejects cache misses whencompiled: true.- Runtime LRU — compiled templates are cached in memory after first read.
- Streaming shell flush —
Response.ssrStream()andView.streamSsr()emit the document<head>(including CSS links) before the first view chunk. Passheadwith your Vite or asset tags for fastest first paint. - Empty hydration skip — pages without
@islandmarkers omit the hydration JSON script entirely.
Route.get('/dashboard', () =>
View.streamSsr('dashboard', context, handlers, {
head: '<link rel="stylesheet" href="/build/app.css">',
}),
);For Turbo/HTMX partial updates without full reloads, see the partial reload cookbook.
ORM throughput
Model.select('id', 'title')— prune columns on wide tables instead ofModel.all(); benchmark keyorm.select.pruned- Prepared statements — SQLite caches
prepare()per connection; Postgres uses named prepared SELECTs; MySQL caches in transactions Model.remember()— cache expensive aggregate query results (see earlier section)Model.insertMany()— batch inserts for seeders
Database & pools
SQLite (file-backed)
Production scaffolds enable WAL journal mode by default (journalMode: 'wal' in config/database.ts). WAL allows concurrent readers while a writer is active — important for SQLite on Fly/Railway with multiple workers.
Postgres / MySQL pool sizing
Start with one pool per worker process, not one global pool for the whole machine:
| Deployment | Suggested DB_POOL_MAX per worker | Notes |
|---|---|---|
| Fly.io (1 shared CPU) | 5–10 | Match tyravel start worker count |
| Railway (512 MB) | 5 | Watch connection limits on hobby Postgres |
| Single VPS (2 workers) | 10 per worker | Total ≤ provider max connections |
Environment variables (driver packages):
DB_POOL_WARMUP— fireSELECT 1on boot (defaulttruein production scaffold)DB_POOL_MAX— max connections per poolDB_POOL_IDLE_TIMEOUT— idle connection eviction in ms
Enable pool warm-up so the first real query does not pay connection setup latency.
Caching
Scaffold config/cache.ts defaults to the file driver. In production with Redis available:
CACHE_STORE=redisWrap expensive reads:
const posts = await Cache.remember('home:posts', 300, async () => {
return Post.query().orderBy('published_at', 'desc').limit(10).getModels();
});For safe public GET routes, add HTTP cache middleware (ETag / 304) from Tier 15. See Cache.
When to use Redis
| Use Redis when… | Skip Redis when… |
|---|---|
| Multiple app workers share sessions | Single-process dev |
Queue driver is redis | Database queue is enough |
| Cache hit rate matters at scale | File cache is fine for low traffic |
| WebSocket broadcast fan-out | Log driver suffices |
Anti-patterns
- N+1 queries — use
with()/ eager loading; enableModel.preventLazyLoading()in development. - Uncached views in production — always run
view:cachebefore deploy; setcompiled: true. - Session on every API route — use JSON fast path; scope session middleware to browser routes only.
- Synchronous boot work — defer admin, debug, and MCP providers (lazy registration) until first use.
- Full page reload for small UI updates — use
View.partial()/Response.partial()instead.
HTTP/2 and clustering
HTTP/2 (Node adapter, TLS required):
await serve(kernel, {
port: 3000,
tls: { certPath: 'storage/certs/local.pem', keyPath: 'storage/certs/local-key.pem' },
http2: true,
});Or set TYRAVEL_HTTP2=1 with TYRAVEL_TLS_CERT / TYRAVEL_TLS_KEY.
Multiple workers — tyravel start --cluster forks node:cluster workers (default: CPU count). Use Redis or database sessions so requests are not pinned to a single process:
tyravel start --cluster --workers=4Single-file bundle
For edge deploys (Fly Machines, Lambda-style), bundle the entry after caches are warm:
tyravel config:cache && tyravel route:cache && tyravel view:cache
npm install -D esbuild
tyravel build --outfile=bootstrap/app.mjs --minify
node bootstrap/app.mjsTrade-offs: faster cold start, but native addons and some dynamic imports may need esbuild plugins. See bootstrap/README.txt after build.
Perf budgets in CI
Add thresholds to tyravel.json:
{
"perf": {
"budgets": {
"http.json": { "min": 500, "unit": "req/s" },
"boot.cold": { "max": 400, "unit": "ms" }
}
}
}Run tyravel test --perf to fail when benchmarks regress (requires scripts/benchmark.mjs in the monorepo or linked checkout).
Measuring
npm run benchmark
BENCHMARK_QUICK=1 npm run benchmark -- --jsonSee Benchmarks for CI snapshots, regression gates, and Bun vs Node notes.
Related
- Deployment — platform hub, clustering, bundles
- Cloudflare — CDN + origin patterns
- Platform matrix
- Headless API — backend-only scaffold
- Views & templating — streaming SSR and islands
- Observability cookbook — production latency signals