Don't install v25.15.5, it's a broken version of titan
The Titan CLI command is now titan.
The previous tit command is still supported as a legacy alias.
titan planet

Runtime APIs

Use built-in runtime APIs inside actions to perform side effects such as logging and outbound HTTP requests.

Overview

Titan provides a small, intentional set of runtime APIs that are available inside actions.
These APIs allow actions to perform controlled side effects while preserving Titan’s performance, determinism, and Rust-backed execution model.

Runtime APIs are exposed through the global t object.

Runtime APIs are not available in routes.
They are designed exclusively for use inside actions.


t.log() — Structured logging

t.log() is Titan’s built-in logging API.
It allows actions to emit logs that are collected and handled by the native Rust server.

t.log("User login started")

Logging structured data

t.log() accepts any serializable JavaScript value.

app/actions/login.js
t.log({
  action: "login",
  userId: req.params.id,
})
  • Objects are logged as structured data
  • Logs are serialized safely
  • No console.log dependency

Why t.log exists

  • Logs are routed through Rust (not stdout hacks)
  • Consistent formatting across environments
  • Safe to use in production
  • Zero Node.js dependency

Use t.log() instead of console.log() in all actions.


t.fetch() — Outbound HTTP requests

t.fetch() allows actions to make outbound HTTP requests. It follows a familiar fetch-style API while executing through Titan’s Rust networking layer.

const res = t.fetch("https://api.example.com/users")

Basic usage

export default function example(req) {
  const res = t.fetch("https://api.example.com/data")
  return res
}
  • Executes via Rust-native HTTP client
  • No Node.js networking stack
  • Predictable performance

Sending a JSON request

app/actions/login.js
t.fetch("https://api.example.com/login", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: {
    email: req.body.email,
  },
})
  • Objects passed as body are serialized automatically
  • Headers are optional
  • No manual JSON handling required

Reading the response

t.fetch() returns a parsed response object.

const res = t.fetch("https://api.example.com/user/1")

return {
  status: res.status,
  data: res.body,
}
  • res.status → HTTP status code
  • res.body → parsed response body
  • Errors propagate naturally to the caller

Error behavior

If a request fails:

  • Network errors throw immediately
  • Non-2xx responses are still returned
  • You control how failures are handled
const res = t.fetch(url)

if (res.status !== 200) {
  t.log("Upstream service failed")
}

t.jwt — JSON Web Tokens

t.jwt provides Rust-backed JSON Web Token (JWT) signing and verification. All cryptographic operations are executed natively in Rust.

There is no Node.js JWT library, no JS crypto, and no async behavior.


t.jwt.sign()

Creates and signs a JWT.

const token = t.jwt.sign(
  { userId: 1, email: "admin@ez.app" },
  processe.env.JWT_SECRET,
  { expiresIn: "1m" }
)

Parameters

  • payload — Object to encode into the token
  • secret — HMAC secret key
  • options (optional)

Supported expiresIn formats

ValueMeaning
6060 seconds
"1m"1 minute
"1h"1 hour
"30d"30 days

Expiration is converted into a JWT exp claim inside Rust.

If expiresIn is omitted, the token does not expire.


t.jwt.verify()

Verifies a JWT and returns its decoded payload.

const payload = t.jwt.verify(token, processe.env.JWT_SECRET)

Behavior

  • Signature is validated
  • exp (expiration) is enforced
  • Expired tokens throw immediately
  • Time comparison is done in Rust
try {
  const payload = t.jwt.verify(token, processe.env.JWT_SECRET)
} catch {
  // invalid or expired token
}

jwt.io may decode expired tokens, but Titan correctly rejects them.

Error log on expired token

Titan Runtime APIs

t.password — Password hashing

t.password provides secure password hashing and verification using Rust-native cryptography.

Passwords are never processed by JavaScript libraries.


t.password.hash()

Hashes a plaintext password.

const hash = t.password.hash("admin123")
  • Uses a secure adaptive hashing algorithm
  • Safe to store in a database
  • Deterministic and production-ready

t.password.verify()

Verifies a password against a stored hash.

const ok = t.password.verify("admin123", hash)
  • Returns true if the password matches
  • Returns false otherwise
  • No timing-sensitive logic in JavaScript

Security guarantees

  • No plaintext passwords stored
  • No JS-side cryptography
  • No implicit expiration handling
  • All verification enforced in Rust

Where Runtime APIs can be used

LocationAllowed
Routes❌ No
Actions✅ Yes
Build time❌ No

Runtime APIs execute only at request time.


Design philosophy

Titan’s runtime APIs are:

  • Minimal by design
  • Explicitly scoped
  • Rust-backed
  • Production-safe

There is no hidden magic and no implicit globals beyond t


Mental model

Routes define structure Actions define behavior Runtime APIs perform side effects Rust executes everything

This keeps Titan applications predictable, fast, and maintainable.

Example Actions

credentials
{
  "email": "admin@ez.app",
  "password": "mypassword123"
}

Login to the account

app/action/login.js
export function login(req) {
    const { email, password } = req.body || {}
  
    if (!email || !password) {
      return {
        status: 400,
        json: { error: "Email and password required" }
      }
    }
  
    // ⚠️ Mock DB
    const user = {
      id: 1,
      email: "admin@ez.app",
      passwordHash: "$2b$12$MJwttSgptEQJCkPJ.J8mce1xxtmxlJPCsISvc1WEzR6mqdD/ZJyOC"
    }
  
    if (email !== user.email) {
      return {
        status: 401,
        json: { error: "Invalid credentials" }
      }
    }
  
    const ok = t.password.verify(password, user.passwordHash)
  
    if (!ok) {
      return {
        status: 401,
        json: { error: "Invalid credentials" }
      }
    }
  
    const token = t.jwt.sign(
      { userId: user.id, email: user.email },
      processe.env.JWT_SECRET,
      { expiresIn: "1m" }   // 👈 1 minute token
    )
  
    return {
      status: 200,
      json: {
        token,
        expiresIn: "1 minute"
      }
    }
  }

Register a account

app/action/register.js
export function register(req) {
    const { email, password } = req.body || {}
  
    if (!email || !password) {
      return {
        status: 400,
        json: { error: "Email and password are required" }
      }
    }
  
    // ⚠️ Mock DB
    // IMPORTANT: store passwordHash, never password
    const passwordHash = t.password.hash(password)
  
    // pretend we saved this
    const user = {
      id: 1,
      email,
      passwordHash
    }
  
    return {
      status: 201,
      json: {
        message: "Account created",
        user: {
          id: user.id,
          email: user.email,
          passwordHash: user.passwordHash
        }
      }
    }
  }

Get the user details

app/action/getUser.js
export function getUser(req) {
    const { token } = req.body || {}
  
    const payload = t.jwt.verify(token, processe.env.JWT_SECRET)
  
    return {
      status: 200,
      json: {
        user: payload
      }
    }
  }

On this page