Environment Variables#
⚠️ BREAKING CHANGE: Tina4 v3.12.0
Every framework env var now requires the
TINA4_prefix. The legacy un-prefixed names (DATABASE_URL,SECRET,SMTP_HOST,HOST_NAME, etc.) no longer work. Setting them at startup makes the framework refuse to boot with a list of renames.Run
tina4 env --migrateto rewrite your existing.envautomatically, or rename manually using the table below. The runtime guard prints the same mapping if it detects legacy names.Conventional names stay un-prefixed:
PORT,HOST,NODE_ENV,RACK_ENV,RUBY_ENV,ENVIRONMENT. These are runtime/PaaS conventions, not framework config.
Tina4 Ruby is configured through environment variables, read from .env at the project root. Every variable has a sensible default, so most projects set three or four values and leave the rest alone.
This chapter lists every variable the Ruby framework reads, grouped by subsystem. Start with the minimum-config examples at the end, then come back here when you need to tune something specific.
Core Server#
| Variable | Default | Description |
|---|---|---|
HOST | 0.0.0.0 | Bind address. 0.0.0.0 listens on every interface. 127.0.0.1 restricts to localhost. |
TINA4_HOST | (inherits HOST) | Tina4-specific alias for HOST. |
PORT | 7147 | HTTP server port. The Rust CLI prefers TINA4_PORT but falls back to PORT. |
TINA4_PORT | (inherits PORT) | Explicit Tina4-specific port override. Takes precedence over PORT when both are set. |
TINA4_HOST_NAME | localhost:7147 | Fully-qualified host used in generated absolute URLs (Swagger, OAuth redirects, emails). |
TINA4_DEBUG | false | Master debug toggle. Enables Swagger UI, dev dashboard, live reload, template dump filter, error overlay. Never set to true in production. |
TINA4_ENV | development | Runtime environment label. Values like development, staging, production control dev-only features. Falls back to RACK_ENV then RUBY_ENV. |
RACK_ENV | (none) | Rack-standard environment label. Used if TINA4_ENV is unset. |
RUBY_ENV | (none) | Ruby-ecosystem environment label. Used if TINA4_ENV and RACK_ENV are unset. |
TINA4_NO_BROWSER | false | Stops tina4 serve from opening your browser on every restart. Recommended during active development. |
TINA4_NO_RELOAD | false | Disables the dev hot-reload signal from the Rust CLI. Use when you want a stable server for debugging. |
ENVIRONMENT | (none) | PaaS-style environment label. Read by tooling alongside RACK_ENV/RUBY_ENV. |
TINA4_SHUTDOWN_TIMEOUT | 10 | Seconds the supervisor waits for graceful shutdown before terminating workers. |
TINA4_SUPERVISOR_URL | (derived from TINA4_PORT + 2000) | Override URL for the local Rust CLI supervisor used by the dev dashboard. |
TINA4_TEMPLATE_ROUTING | on | Controls automatic template-to-route binding. Set to off, false, 0, no, or disabled to require explicit route declarations. |
TINA4_ALLOW_LEGACY_ENV | false | Bypass the v3.12 legacy-env startup guard. Intended for CI/migration scripts only. |
TINA4_SUPPRESS | false | Suppresses the startup banner. Useful for headless processes and CI runs. |
TINA4_ENV_FILE | .env | Path or filename of the dotenv file loaded at boot. Resolved against the project root when relative. |
TINA4_HEALTH_PATH | /__health | Health-check route mounted by Tina4::Health. The legacy /health path stays registered as an alias unless it's the configured value. |
Routing#
| Variable | Default | Description |
|---|---|---|
TINA4_TRAILING_SLASH_REDIRECT | false | When truthy, the Rack app issues a 301 redirect that strips trailing slashes from request paths. |
Secrets and Authentication#
| Variable | Default | Description |
|---|---|---|
TINA4_SECRET | tina4-default-secret | JWT signing secret. Must be long, random, and unique per environment. Never commit. |
TINA4_TOKEN_LIMIT | 60 | JWT token lifetime in minutes. |
TINA4_JWT_ALGORITHM | HS256 | JWT signing algorithm. |
TINA4_API_KEY | (empty) | Static API key used by Tina4::Auth.validate_api_key as a fallback to JWT. |
TINA4_API_KEY | (empty) | Legacy alias for TINA4_API_KEY. |
Database#
| Variable | Default | Description |
|---|---|---|
TINA4_DATABASE_URL | (required for non-SQLite) | Connection URL. Scheme selects the driver: sqlite, postgres, mysql, firebird. |
TINA4_DATABASE_USERNAME | (empty) | Overrides the username embedded in TINA4_DATABASE_URL. |
TINA4_DATABASE_PASSWORD | (empty) | Overrides the password embedded in TINA4_DATABASE_URL. |
TINA4_DATABASE_FIREBIRD_PATH | (empty) | Overrides the database path/alias parsed from TINA4_DATABASE_URL for Firebird. Useful for Windows backslash paths and split-config setups. |
TINA4_DATABASE_URL | (empty) | Legacy alias for TINA4_DATABASE_URL. |
TINA4_AUTOCOMMIT | true | Standalone writes auto-commit on their own connection (durable + visible across a pool); explicit transactions stay atomic. Set false for strict manual-commit mode. |
TINA4_DB_CACHE | false | Enables in-memory query-result caching for read queries. |
TINA4_DB_CACHE_TTL | 30 | Query cache TTL in seconds when TINA4_DB_CACHE=true. |
TINA4_ORM_PLURAL_TABLE_NAMES | true | When true, the ORM pluralises class names into table names (User → users). Set false to keep them singular. |
TINA4_DB_POOL | 0 | Connection pool size used by Tina4::Database.new(url, pool:) when the caller doesn't pass pool: explicitly. 0 disables pooling. |
CORS#
| Variable | Default | Description |
|---|---|---|
TINA4_CORS_ORIGINS | * | Comma-separated allowed origins. Lock down to real domains in production. |
TINA4_CORS_METHODS | GET, POST, PUT, PATCH, DELETE, OPTIONS | Allowed request methods. |
TINA4_CORS_HEADERS | Content-Type,Authorization,X-Request-ID | Allowed request headers. |
TINA4_CORS_CREDENTIALS | false | Send Access-Control-Allow-Credentials: true. |
TINA4_CORS_MAX_AGE | 86400 | Preflight cache lifetime in seconds. |
Security Headers#
| Variable | Default | Description |
|---|---|---|
TINA4_CSP | default-src 'self' | Content-Security-Policy header. |
TINA4_CSRF | false | CSRF token validation on POST/PUT/PATCH/DELETE. Off by default in Ruby; enable with true. |
TINA4_HSTS | (empty/off) | Strict-Transport-Security max-age in seconds. Set 31536000 in production with HTTPS. |
TINA4_FRAME_OPTIONS | SAMEORIGIN | X-Frame-Options header. |
TINA4_REFERRER_POLICY | strict-origin-when-cross-origin | Referrer-Policy header. |
TINA4_PERMISSIONS_POLICY | camera=(), microphone=(), geolocation=() | Permissions-Policy header. |
Rate Limiting#
| Variable | Default | Description |
|---|---|---|
TINA4_RATE_LIMIT | 100 | Maximum requests per window per IP. Set 0 to disable. |
TINA4_RATE_WINDOW | 60 | Rate-limit window in seconds. |
Sessions#
| Variable | Default | Description |
|---|---|---|
TINA4_SESSION_BACKEND | file | Storage backend. Options: file, redis, valkey, mongo, database. |
TINA4_SESSION_TTL | 3600 | Session expiry in seconds. |
TINA4_SESSION_SAMESITE | Lax | SameSite cookie attribute. Options: Strict, Lax, None. |
TINA4_SESSION_PATH | data/sessions | Filesystem path for the file backend. |
TINA4_SESSION_NAME | tina4_session | Session cookie name. Used unless the caller passes an explicit cookie_name. |
TINA4_SESSION_HTTPONLY | true | Sets the HttpOnly attribute on the session cookie. Set false to allow JavaScript access. |
TINA4_SESSION_SECURE | false | Sets the Secure attribute on the session cookie. Enable in production behind HTTPS. |
Valkey/Redis session backend#
| Variable | Default | Description |
|---|---|---|
TINA4_SESSION_VALKEY_HOST | localhost | Valkey/Redis host for the session handler. |
TINA4_SESSION_VALKEY_PORT | 6379 | Valkey/Redis port. |
TINA4_SESSION_VALKEY_PASSWORD | (none) | Valkey/Redis auth password. |
TINA4_SESSION_VALKEY_DB | 0 | Valkey/Redis database number. |
TINA4_SESSION_VALKEY_PREFIX | tina4:session: | Key prefix used for session entries. |
TINA4_SESSION_VALKEY_TTL | 86400 | Per-key expiry in seconds. |
Cache#
| Variable | Default | Description |
|---|---|---|
TINA4_CACHE_BACKEND | memory | Response cache backend. Options: memory, file, redis, valkey, memcached, mongodb, database. Falls back to file if the configured backend is unreachable. |
TINA4_CACHE_DIR | data/cache | Cache directory for the file backend. |
TINA4_CACHE_TTL | 0 | Default cache TTL in seconds (0 disables caching for the global instance; the singleton helper uses 60 when unset). |
TINA4_CACHE_MAX_ENTRIES | 1000 | Maximum cache entries before eviction. |
TINA4_CACHE_URL | redis://localhost:6379 | Connection URL for remote cache backends. For database, falls back to TINA4_DATABASE_URL when unset. |
TINA4_CACHE_USERNAME | (none) | Username for the cache backend. May also be embedded in TINA4_CACHE_URL. |
TINA4_CACHE_PASSWORD | (none) | Password for the cache backend. May also be embedded in TINA4_CACHE_URL (e.g. redis://:pass@host). Memcached is unauthenticated. |
Templates#
| Variable | Default | Description |
|---|---|---|
TINA4_TEMPLATE_CACHE_TTL | 0 | Frond template cache TTL in seconds. 0 keeps compiled templates cached permanently; positive values expire entries after N seconds. |
GraphQL#
| Variable | Default | Description |
|---|---|---|
TINA4_GRAPHQL_AUTO_SCHEMA | true | When true, the GraphQL module auto-generates a schema from registered ORM models. Set false to require an explicit schema. |
TINA4_GRAPHQL_ENDPOINT | /graphql | Path the GraphQL handler is mounted at when the caller doesn't pass an explicit path. |
Queues#
| Variable | Default | Description |
|---|---|---|
TINA4_QUEUE_BACKEND | file | Queue backend. Options: file, kafka, rabbitmq, mongo, database. |
TINA4_QUEUE_URL | (none) | Connection URL for remote backends. Parsed for host/port when set. |
Kafka queue backend#
| Variable | Default | Description |
|---|---|---|
TINA4_KAFKA_BROKERS | (none) | Comma-separated broker list (e.g. localhost:9092). |
TINA4_KAFKA_GROUP_ID | tina4_consumer_group | Kafka consumer group ID. |
RabbitMQ queue backend#
| Variable | Default | Description |
|---|---|---|
TINA4_RABBITMQ_HOST | localhost | RabbitMQ host. |
TINA4_RABBITMQ_PORT | 5672 | RabbitMQ port. |
TINA4_RABBITMQ_USERNAME | guest | RabbitMQ username. |
TINA4_RABBITMQ_PASSWORD | guest | RabbitMQ password. |
TINA4_RABBITMQ_VHOST | / | RabbitMQ virtual host. |
MongoDB queue backend#
| Variable | Default | Description |
|---|---|---|
TINA4_MONGO_URI | (none) | Full MongoDB connection string. Overrides host/port when set. |
TINA4_MONGO_HOST | localhost | MongoDB host. |
TINA4_MONGO_PORT | 27017 | MongoDB port. |
TINA4_MONGO_USERNAME | (none) | MongoDB username. |
TINA4_MONGO_PASSWORD | (none) | MongoDB password. |
TINA4_MONGO_DB | tina4 | MongoDB database name. |
TINA4_MONGO_COLLECTION | tina4_queue | MongoDB collection name for jobs. |
WebSocket#
| Variable | Default | Description |
|---|---|---|
TINA4_WS_BACKPLANE | (none) | Backplane type. Options: redis, nats. Required for multi-instance broadcasts. |
TINA4_WS_BACKPLANE_URL | redis://localhost:6379 (Redis) / nats://localhost:4222 (NATS) | Connection URL for the chosen backplane. |
Email#
| Variable | Default | Description |
|---|---|---|
TINA4_MAIL_HOST | localhost | SMTP server hostname. |
TINA4_MAIL_PORT | 587 | SMTP server port. |
TINA4_MAIL_USERNAME | (none) | SMTP authentication username. |
TINA4_MAIL_PASSWORD | (none) | SMTP authentication password. |
TINA4_MAIL_FROM | dev@localhost | Default sender email address. |
TINA4_MAIL_FROM_NAME | (empty) | Default sender display name. |
TINA4_MAIL_ENCRYPTION | tls | Connection encryption. Options: tls, ssl, none. |
TINA4_MAIL_IMAP_HOST | (inherits mail host) | IMAP server for inbound mail. |
TINA4_MAIL_IMAP_PORT | 993 | IMAP server port. |
TINA4_MAIL_IMAP_USERNAME | (inherits SMTP username) | IMAP authentication username. Mapped from legacy IMAP_USER. |
TINA4_MAIL_IMAP_PASSWORD | (inherits SMTP password) | IMAP authentication password. Mapped from legacy IMAP_PASS. |
TINA4_MAIL_IMAP_ENCRYPTION | tls | IMAP connection encryption. Accepts tls, starttls, or none. |
TINA4_MAIL_CAPTURE | false | Force local DevMailbox capture and skip SMTP, even when an SMTP host exists. A missing host also captures. |
TINA4_MAIL_REDIRECT_TO | (none) | Comma-separated safety recipients for real SMTP delivery. Replaces To, Cc, and Bcc. |
TINA4_MAILBOX_DIR | data/mailbox | Storage directory for captured mail. This setting does not enable or disable capture. |
TINA4_DEBUGdoes not suppress email. On staging, setTINA4_MAIL_CAPTURE=trueto keep every message local, or setTINA4_MAIL_REDIRECT_TO=qa@example.com,product@example.comto exercise SMTP without reaching original recipients. Capture takes precedence when both are set.
TINA4_MAIL_HOST,TINA4_MAIL_PORT,TINA4_MAIL_USERNAME,TINA4_MAIL_PASSWORD,TINA4_MAIL_FROM,TINA4_MAIL_FROM_NAME,TINA4_MAIL_IMAP_HOST,TINA4_MAIL_IMAP_PORTare accepted as legacy aliases. New projects should use theTINA4_MAIL_*names.
Logging#
| Variable | Default | Description |
|---|---|---|
TINA4_LOG_LEVEL | [TINA4_LOG_ALL] | Console log level. Options: [TINA4_LOG_ALL], [TINA4_LOG_DEBUG], [TINA4_LOG_INFO], [TINA4_LOG_WARNING], [TINA4_LOG_ERROR], [TINA4_LOG_NONE]. Also accepts plain DEBUG, INFO, ERROR, etc. |
TINA4_LOG_MAX_SIZE | 10 | Per-file log size limit in megabytes. Rotated when exceeded. |
TINA4_LOG_KEEP | 5 | Number of rotated log files to retain. |
Logs default to stdout. Set TINA4_LOG_OUTPUT=file plus TINA4_LOG_FILE=app.log to write to disk; Ruby's stdlib Logger rotates at TINA4_LOG_ROTATE_SIZE bytes and keeps TINA4_LOG_ROTATE_KEEP backups natively.
| Variable | Default | Description |
|---|---|---|
TINA4_LOG_FILE | (empty = stdout only) | Explicit log file path. Absolute, or resolved relative to TINA4_LOG_DIR. |
TINA4_LOG_DIR | logs | Directory used when TINA4_LOG_FILE is set without an absolute path. |
TINA4_LOG_FORMAT | text | Log line format. Accepts text or json. |
TINA4_LOG_OUTPUT | stdout | Output sink. Accepts stdout, file, or both. |
TINA4_LOG_CRITICAL | false | When true, gates the new critical level and raises on log write failures instead of swallowing them. |
TINA4_LOG_ROTATE_SIZE | 10485760 | Per-file rotation threshold in bytes (10 MB). 0 disables rotation. Handled natively by stdlib Logger.new(path, shift_age, shift_size). |
TINA4_LOG_ROTATE_KEEP | 5 | Number of rotated backups to retain. |
Uploads#
| Variable | Default | Description |
|---|---|---|
TINA4_MAX_UPLOAD_SIZE | 10485760 | Maximum multipart upload size in bytes (10 MB). Requests larger than this are rejected before parsing. |
Services (background tasks)#
| Variable | Default | Description |
|---|---|---|
TINA4_SERVICE_DIR | src/services | Directory scanned for service classes. |
TINA4_SERVICE_SLEEP | 5 | Seconds the service runner sleeps between iterations. |
Localisation#
| Variable | Default | Description |
|---|---|---|
TINA4_LOCALE | en | Default locale for Tina4::Localization. |
TINA4_LOCALE_DIR | src/locale | Directory containing locale JSON files. |
Application AI Client and Developer AI Tools#
The app-facing Ai client and the developer dashboard share the TINA4_AI_* namespace. The client supports local OpenAI-compatible servers, OpenAI, and Anthropic. See Chapter 39: AI Client for code examples.
| Variable | Default | Description |
|---|---|---|
TINA4_AI_PROVIDER | local | Provider used by the app-facing client: local, openai, or anthropic. |
TINA4_AI_URL | Provider-specific | Base URL or full endpoint. Local defaults to http://localhost:11437; OpenAI and Anthropic use their public API bases. |
TINA4_AI_MODEL | Provider-specific | Default model. Local uses llama3.2, OpenAI uses gpt-4o-mini, and Anthropic uses claude-3-5-haiku-latest. |
TINA4_AI_KEY | (none) | Required before an OpenAI or Anthropic request. Local requests need no key. |
TINA4_AI_TIMEOUT | 60 | Total request deadline in seconds, including retries and response reads. |
TINA4_AI_CONNECT_TIMEOUT | 10 | Connection-establishment deadline in seconds. |
TINA4_AI_MAX_RETRIES | 2 | Retries before output for connection failures, HTTP 429, and HTTP 5xx. |
TINA4_EMBED_URL | (inherits TINA4_AI_URL) | Optional embedding base URL or full endpoint. |
TINA4_RAG_URL | http://localhost:11438 | RAG service used by the developer dashboard. |
TINA4_RAG_TOPK | 4 | Number of RAG matches returned per query. |
TINA4_VISION_URL | http://localhost:11437/api/chat | Vision endpoint used by developer tools, not the app-facing AI client. |
TINA4_IMAGE_URL | http://localhost:11437/api/generate | Image endpoint used by developer tools, not the app-facing AI client. |
TINA4_SUPERVISOR_URL | http://localhost:9999 | Rust supervisor URL used by developer tools. |
TINA4_MCP_REMOTE | false | Allows MCP to bind beyond localhost. Do not enable it on a public production interface. |
TINA4_NO_AI_PORT | false | Disables the developer AI port listener. |
TINA4_OVERRIDE_CLIENT | false | Lets the framework start without the Rust client in containers and CI. |
MCP#
| Variable | Default | Description |
|---|---|---|
TINA4_MCP | (inherits TINA4_DEBUG) | Enables the MCP server. Defaults to whatever TINA4_DEBUG is set to; pass true/false to override explicitly. |
TINA4_MCP_PORT | (derived from TINA4_PORT + 2000) | Port the MCP server binds to. Defaults to the HTTP port plus 2000. |
Swagger / OpenAPI#
| Variable | Default | Description |
|---|---|---|
TINA4_SWAGGER_TITLE | Tina4 API | OpenAPI spec title. Falls back to PROJECT_NAME. |
TINA4_SWAGGER_DESCRIPTION | Auto-generated API documentation | OpenAPI spec description. |
TINA4_SWAGGER_VERSION | (Gem version) | Overrides the spec version. |
TINA4_SWAGGER_ENABLED | (inherits TINA4_DEBUG) | Enables the Swagger UI and /swagger.json route. Defaults to TINA4_DEBUG; set explicitly to override. |
TINA4_SWAGGER_CONTACT_EMAIL | (empty) | Contact email rendered into the OpenAPI info.contact block. |
TINA4_SWAGGER_LICENSE | (empty) | SPDX license name (e.g. MIT) rendered into the OpenAPI info.license block. |
PROJECT_NAME | (none) | Alternative OpenAPI title source when TINA4_SWAGGER_TITLE is unset. |
Configuration Recipes#
The tables above list every knob. These are the setups most apps actually reach for, ready to paste into .env. Each block sets only what the feature needs. Everything else keeps its default.
PostgreSQL in production#
One URL points the ORM, the migrations, and the query builder at Postgres. Credentials can ride in the URL or sit in their own variables, which keeps the password out of your shell history.
TINA4_DATABASE_URL=postgresql://localhost:5432/myappTINA4_DATABASE_USERNAME=myappTINA4_DATABASE_PASSWORD=changemeTINA4_DB_POOL=4TINA4_DB_POOL=4 opens four connections and rotates across them. Leave it at 0 for a single connection on a small app.
A shared cache on Redis#
The response cache and the cross-request query cache both speak to the same Redis. Point them at it and every instance shares one cache, invalidated globally on every write.
TINA4_CACHE_BACKEND=redisTINA4_CACHE_URL=redis://localhost:6379TINA4_DB_CACHE=trueTINA4_DB_CACHE_BACKEND=redisTINA4_DB_CACHE_URL=redis://localhost:6379If Redis is down or the driver is missing, the cache logs a warning and falls back to the file backend. It never silently stops caching.
Sessions that survive more than one box#
The file backend is fine for a single server. Move sessions to Redis the moment you run more than one instance, so a user stays logged in whichever instance answers the next request.
TINA4_SESSION_BACKEND=redisTINA4_SESSION_REDIS_HOST=localhostTINA4_SESSION_REDIS_PORT=6379TINA4_SESSION_SECURE=trueTINA4_SESSION_SAMESITE=StrictTINA4_SESSION_SECURE=true keeps the cookie off plain HTTP. Turn it on once you have TLS.
A queue on RabbitMQ or Kafka#
One URL is enough for RabbitMQ; the per-field variables only exist for split configs. The queue API stays identical whichever backend you pick.
TINA4_QUEUE_BACKEND=rabbitmqTINA4_QUEUE_URL=amqp://guest:guest@localhost:5672/Kafka reads a broker list instead:
TINA4_QUEUE_BACKEND=kafkaTINA4_KAFKA_BROKERS=localhost:9092TINA4_KAFKA_GROUP_ID=myapp_workersWebSocket broadcasts across instances#
A single server broadcasts in memory. Add a backplane and a message sent on one instance reaches clients connected to every other instance.
TINA4_WS_BACKPLANE=redisTINA4_WS_BACKPLANE_URL=redis://localhost:6379TINA4_WS_ALLOWED_ORIGINS=https://myapp.comSet the origin allow-list in production. Empty allows every origin, which is fine in dev and risky on the public internet.
Locked-down production headers#
The defaults are already safe. These four tighten the screws for a public site on HTTPS.
TINA4_CORS_ORIGINS=https://myapp.com,https://www.myapp.comTINA4_HSTS=31536000TINA4_FRAME_OPTIONS=DENYTINA4_SESSION_SECURE=trueNever pair TINA4_CORS_CREDENTIALS=true with TINA4_CORS_ORIGINS=*. Name your real origins instead.
The dev dashboard AI, kept local#
The dashboard AI talks to a local model through Ollama by default, so nothing leaves your machine. Point the URLs elsewhere only when you run the hosted Tina4 AI services.
TINA4_AI_URL=http://localhost:11437/api/chatTINA4_AI_MODEL=qwen2.5-coder:14bTINA4_RAG_URL=http://localhost:11438Minimal .env for Development#
TINA4_DEBUG=trueTINA4_LOG_LEVEL=ALLTINA4_NO_BROWSER=trueDebug mode lights up the Swagger UI, the dev dashboard, detailed error pages, and live reload. Keeping the browser flag on stops a new tab opening every time you save a file.
Minimal .env for Production#
TINA4_SECRET=your-long-random-secret-hereTINA4_DATABASE_URL=postgresql://user:password@db-host:5432/myappTINA4_CORS_ORIGINS=https://myapp.com,https://www.myapp.comTINA4_HSTS=31536000TINA4_MAIL_HOST=smtp.example.comTINA4_MAIL_PORT=587TINA4_MAIL_USERNAME=noreply@myapp.comTINA4_MAIL_PASSWORD=your-smtp-passwordTINA4_MAIL_FROM=noreply@myapp.comNo TINA4_DEBUG. It defaults to false, which is what you want in production. Set a real secret, a real database, locked-down CORS origins, HSTS, and SMTP credentials if you send email. Everything else has a production-appropriate default.