Configuration
Configure your Lithia application with lithia.config.ts
Introduction
Lithia uses a configuration file (lithia.config.ts) to customize server behavior, CORS settings, and other framework options. Unlike traditional frameworks that require entry point files, Lithia handles server initialization automatically - you just configure how it should run.
The configuration file is optional. If you don't provide one, Lithia uses sensible defaults.
Basic Configuration
Create lithia.config.ts in your project root:
import { defineLithiaConfig } from 'lithia';
export default defineLithiaConfig({
server: {
port: 3000,
host: 'localhost'
}
});The defineLithiaConfig helper provides TypeScript autocomplete and validation.
Configuration Options
Server Configuration
Control how your server runs:
export default defineLithiaConfig({
server: {
port: 3000, // Port to listen on (default: 3000)
host: 'localhost', // Host to bind to (default: 'localhost')
request: {
maxBodySize: 1024 * 1024, // Max request body size in bytes (default: 1MB)
queryParser: {
array: {
enabled: true, // Parse array query params (default: true)
delimiter: ',' // Array delimiter (default: ',')
},
number: {
enabled: true // Parse numbers automatically (default: true)
},
boolean: {
enabled: true // Parse booleans automatically (default: true)
}
}
}
}
});Query parser examples:
With default configuration, Lithia automatically parses query parameters:
| URL | Parsed as |
|---|---|
?page=1 | { page: 1 } (number) |
?active=true | { active: true } (boolean) |
?tags=red,blue,green | { tags: ['red', 'blue', 'green'] } (array) |
?name=John | { name: 'John' } (string) |
To disable automatic parsing:
export default defineLithiaConfig({
server: {
request: {
queryParser: {
array: { enabled: false },
number: { enabled: false },
boolean: { enabled: false }
}
}
}
});Now everything is parsed as strings: ?page=1 → { page: "1" }
CORS Configuration
Configure Cross-Origin Resource Sharing for your API:
export default defineLithiaConfig({
cors: {
origin: ['https://myapp.com', 'https://admin.myapp.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Custom-Header'],
exposedHeaders: ['X-Total-Count', "X-Powered-By"],
credentials: true,
maxAge: 86400, // 24 hours in seconds
optionsSuccessStatus: 204
}
});Default CORS values:
{
origin: ['*'], // Allow all origins
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: [],
credentials: false,
maxAge: 86400,
optionsSuccessStatus: 204
}Common CORS configurations:
export default defineLithiaConfig({
cors: {
origin: ['*'],
credentials: false
}
});export default defineLithiaConfig({
cors: {
origin: [
'https://myapp.com',
'https://www.myapp.com'
],
credentials: true
}
});Debug Mode
Enable debug logging for development:
export default defineLithiaConfig({
debug: true // Enable detailed logging (default: false)
});By default, debug mode is automatically enabled when DEBUG environment variable is set to true, but it'll be overrided by the debug option.
Build Configuration
Configure the build process:
export default defineLithiaConfig({
build: {
builder: 'swc' // Currently only 'swc' is supported
}
});Studio Configuration
Enable or disable the Lithia Studio development UI:
export default defineLithiaConfig({
studio: {
enabled: true // Enable Studio on port 8473 (default: false)
}
});When enabled, access the Studio at http://localhost:8473.
Note: Studio always runs on port 8473 and cannot be changed.
Hooks Configuration
Configure lifecycle hooks for your application. Hooks allow you to run custom code at specific points in the request and middleware lifecycle.
Request Lifecycle Hooks
export default defineLithiaConfig({
hooks: {
// Called before request processing
'request:before': async (req, res) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
// Add custom request context
req.set('requestId', crypto.randomUUID());
req.set('startTime', Date.now());
},
// Called after request processing
'request:after': async (req, res) => {
// Get custom request context
const duration = Date.now() - req.get<number>('startTime');
const requestId = req.get<string>('requestId');
console.log(`Request ${requestId} completed with status ${res.statusCode} in ${duration}ms`);
},
// Called when request processing throws an error
'request:error': async (req, res, error) => {
const requestId = req.get<string>('requestId');
console.error(`Request ${requestId} failed:`, error);
// Send error to monitoring service
await errorTracking.captureException(error, {
request: {
method: req.method,
url: req.url,
headers: req.headers
}
});
}
}
});The request context set in the hooks system is available to all middleware and route handlers.
See more about the request context in Request.
Middleware Lifecycle Hooks
export default defineLithiaConfig({
hooks: {
// Called before each middleware execution
'middleware:beforeExecute': async (middleware, req, res) => {
console.log(`Executing middleware: ${middleware.name}`);
// Track middleware execution time
const middlewareTimings = req.get<Record<string, number>>('middlewareTimings') || {};
middlewareTimings[middleware.name] = Date.now();
req.set('middlewareTimings', middlewareTimings);
},
// Called after each middleware execution
'middleware:afterExecute': async (middleware, req, res) => {
const middlewareTimings = req.get<Record<string, number>>('middlewareTimings') || {};
const duration = Date.now() - middlewareTimings[middleware.name];
console.log(`Middleware ${middleware.name} completed in ${duration}ms`);
},
// Called when middleware throws an error
'middleware:error': async (middleware, req, res, error) => {
console.error(`Middleware ${middleware.name} failed:`, error);
}
}
});Available Hook Types
| Hook | Parameters | Description |
|---|---|---|
request:before | req, res | Called before request processing starts |
request:after | req, res | Called after request processing completes |
request:error | req, res, error | Called when request processing fails |
middleware:beforeExecute | middleware, req, res | Called before each middleware executes. middleware contains info about the middleware (name, position, route) |
middleware:afterExecute | middleware, req, res | Called after each middleware completes |
middleware:error | middleware, req, res, error | Called when middleware throws an error |
See more about the hook types in API Reference.
See Hooks for more advanced hook patterns and best practices.
Environment-Based Configuration
Use environment variables to customize configuration per environment:
import { defineLithiaConfig } from 'lithia';
const isDev = process.env.NODE_ENV !== 'production';
export default defineLithiaConfig({
debug: isDev,
server: {
port: parseInt(process.env.PORT || '3000'),
host: process.env.HOST || 'localhost'
},
cors: {
origin: isDev
? ['*']
: process.env.ALLOWED_ORIGINS?.split(',') || [],
credentials: !isDev
},
});For security reasons, studio only runs with Lithia.js development server.
Troubleshooting
Configuration not loading
Make sure your file is named exactly lithia.config.ts and is in the project root:
my-app/
├── src/
├── lithia.config.ts ← Must be here
├── package.json
└── tsconfig.jsonTypeScript errors
If you get TypeScript errors, ensure you have the correct imports:
import { defineLithiaConfig } from 'lithia';
export default defineLithiaConfig({
// Configuration here
});CORS issues
If you're getting CORS errors:
- Check your
originconfiguration matches your frontend URL exactly - Enable
credentials: trueif using cookies/auth - Add required headers to
allowedHeaders
export default defineLithiaConfig({
cors: {
origin: ['http://localhost:5173'], // Exact match required
credentials: true,
allowedHeaders: ['Content-Type', 'Authorization']
}
});