Skip to content

App config

Every field of AppConfig, with its type, its default and what it does.

AppConfig is the one object you give to Dox().initialize(). It lives in lib/config/app.dart.

Source: packages/dox-core/lib/interfaces/app_config.dart.

Server

Field Type Default Meaning
appKey String required Encrypts cookies (req.cookie(), DoxCookie) and signs local storage URLs. It must be exactly 32 characters. The app stops at start when it is empty, has another length, or is a public sample key. When APP_ENV is development, local, test or testing, this is only a warning. Make one with dox key:generate.
serverPort int 3000 The port the HTTP server listens on. When the env has no APP_PORT but has PORT, Dox listens on PORT instead (Cloud Run, Fly, Render and Heroku set it).
host String? null: APP_HOST, else all interfaces The network interface to listen on, like 127.0.0.1. null reads the env var APP_HOST. With neither, Dox listens on all interfaces, IPv6 and IPv4 (::).
totalIsolate int? Platform.numberOfProcessors Isolates (threads) that serve HTTP, all on the same port. On Windows the native server runs on one isolate.
compress bool false gzip responses (HttpServer.autoCompress). Rust gzips on its own thread, not on the isolate. It still costs CPU on every response. Let a proxy do it when you have one.
maxBodySize int 10 * 1024 * 1024 (10 MB) Biggest JSON or urlencoded body in bytes. Bigger gets 413.
maxMultipartSize int 100 * 1024 * 1024 (100 MB) Biggest multipart/form-data body (file uploads) in bytes. Bigger gets 413.
bodyTimeout Duration Duration(seconds: 120) A client that sends no body bytes for this long gets 408. A slow but steady upload is fine. Native server only.
idleTimeout Duration Duration(seconds: 30) A keep-alive connection with no new request for this long is closed. A request head must also arrive in this time. Behind a load balancer, set it longer than the balancer's idle timeout. See Behind a load balancer.
maxConnections int? null (no limit) The most connections one isolate holds open at once. Must be 1 or more. 0 or less throws an ArgumentError when the server starts. When it is full, new clients wait in the OS listen queue until a connection closes. WebSocket connections and connections that are still closing count too. The queue holds up to 1024 clients, and the OS can make it smaller (somaxconn; 128 by default on macOS). When the queue is full, new clients wait and then time out. On Linux each new client goes to one isolate (SO_REUSEPORT), so it can wait for a full isolate even when others have room. The whole app holds up to maxConnections * totalIsolate, so keep that below ulimit -n. Native server only.
shutdownTimeout Duration Duration(seconds: 8) On SIGTERM or SIGINT, how long open requests may run before Dox closes them. Keep it below the kill timeout of your platform. See Graceful shutdown.
trustedProxies List<String> [] IPs or CIDR ranges of reverse proxies. Only when the direct client is in this list does Dox read X-Forwarded-For for req.ip() and X-Forwarded-Proto for req.scheme(). ['*'] trusts any direct client, and takes the right-most X-Forwarded-For hop (the one the proxy added) as the client.

Routing and request handling

Field Type Default Meaning
container void Function(IocContainer)? null Fills the container: registerContainer from lib/generated/container.g.dart. Every isolate runs it. It also gives the routers, providers and model binders. See Dependency injection.
routers List<Router> [] Routers to register first, in this order. Every other Router class comes from container.
globalMiddleware List<dynamic> [] Middleware that runs on every route. A function or an IDoxMiddleware.
dtos List<DtoSchema<Object>> [] Every DTO of the app: dtos from lib/generated/dtos.g.dart. Dox finds the DTO of a controller parameter and of req.validate<T>() with it.
validationMessages MessageResolver? null (English messages) Messages for validation errors, for example in other languages.
responseHandler ResponseHandlerInterface? null A class with DoxResponse handle(DoxResponse res). It sees every response before it is sent.
exceptionHandler ExceptionHandler ExceptionHandler() Reports every unhandled error and turns it into a response. The default logs the error with Logger.warn and the stack with Logger.danger. See Error handling.
providers List<DoxProvider> [] Providers to run first, in this order. Every other DoxProvider class comes from container. Dox runs them in every isolate at start.
webSocketAllowedOrigins List<String>? null (no check) Turns on the Origin check for every Route.websocket route. Only pages of the same host and the listed sites, like https://app.example.com, can open a socket. Other origins get 403. [] means the same host only. allowedOrigins on a route wins over this. With null, any website can open a socket with the cookies of the user, and Dox prints one warning to stderr at start.

Sub configs

Field Type Default Meaning
cors CORSConfig CORSConfig() CORS headers. See CORSConfig.
logger LoggerConfig LoggerConfig() The Logger output. See LoggerConfig.
cache CacheConfig file store in storage/cache, plus a memory store Cache stores for Cache(). See CacheConfig.
session SessionConfig cookie driver, cookie dox_session, 2 hours Settings for SessionMiddleware. See Session.
openApi OpenApiConfig OpenApiConfig() /docs, /openapi.json and /openapi.yaml. See OpenApiConfig.

CORSConfig

Source: packages/dox-core/lib/interfaces/app_config.dart. Headers are set in packages/dox-core/lib/http/http_cors_handler.dart.

A value can be a String ('*' or a comma list) or a List<String>. A null value sends no header.

Field Type Default Header
enabled bool true Send CORS headers. A route can override it with its own cors setting.
origin dynamic null Access-Control-Allow-Origin. One origin, '*', or a list. With a list, Dox sends back only the request origin if it is in the list.
methods dynamic null Access-Control-Allow-Methods
headers dynamic null Access-Control-Allow-Headers
exposeHeaders dynamic null Access-Control-Expose-Headers
credentials bool? null Access-Control-Allow-Credentials
maxAge num? null Access-Control-Max-Age in seconds

Note

With the default CORSConfig() every value is null. So enabled: true alone sends no header. Set origin at least.

LoggerConfig

Field Type Default Meaning
name String '' The name field in each JSON log line.
enabled bool false Turn the Logger on.
prettyPrint bool false true prints colored text. false prints one JSON object per line (for log services).
level String 'info' The lowest level to print: debug, info, warn or error. Logger.success counts as info. Logger.danger counts as error. An unknown value prints every line.

CacheConfig

Source: packages/dox-cache/lib/src/cache_config.dart. Option keys: packages/dox-cache/lib/src/constants/cache_constants.dart.

Field Type Default Meaning
defaultStore String required The store Cache() uses when no store is named.
stores Map<String, Map<String, dynamic>> required Store name to options. Each store needs a driver option.

Options of each driver:

Driver Option Type Default Meaning
all driver String required file, memory, redis or null
all prefix String dox_cache: Text in front of every key.
file path String storage/cache Folder of the cache files.
memory max_size int no limit Most items in the map.
redis host String 127.0.0.1 Redis host.
redis port int 6379 Redis port.
redis username String none Redis user.
redis password String none Redis password.
redis db int 0 Redis database number.
redis tls bool false Use TLS.
redis pool_size int 10 Most connections per store.

StorageConfig

StorageProvider of the dox_storage package takes it. See File storage. Source: lib/src/dox/storage_config.dart in dartondox/dox-storage.

Field Type Default Meaning
defaultDisk String 'local' The disk Storage() uses when no disk is named.
disks Map<String, Map<String, dynamic>> {'local': {'driver': 'local', 'root': 'storage'}} Disk name to options. Each disk needs a driver option.

Options of each driver:

Driver Option Type Default Meaning
all driver String required local, s3 or memory
local root String storage Folder of the files.
local url String none Base of the public URLs, like http://localhost:3000/files.
local app_key String AppConfig.appKey Key that signs the URLs.
local visibility String public public or private.
s3 bucket String required Bucket name.
s3 region String us-east-1 Region.
s3 key String required Access key id.
s3 secret String required Secret access key.
s3 token String none Session token.
s3 endpoint String none Custom endpoint (R2, MinIO, Spaces).
s3 path_style bool false Use path style URLs.
s3 url String none Base of the public URLs.
s3 visibility String private public or private.
s3 acl bool true The service supports ACLs.
s3 batch_delete bool true The service supports batch delete.

An unknown driver throws ArgumentError('Storage disk "<name>" has unknown driver "<type>"').

OpenApiConfig

Source: packages/dox-core/lib/openapi/openapi_config.dart.

Field Type Default Meaning
enabled bool? null Serve the docs routes. null means: on only when APP_ENV is development or local. An empty APP_ENV counts as production.
info Info Info(title: 'Dox API', version: '1.0.0') Title and version of the API.
servers List<Server> [] Base URLs of the API.
securitySchemes Map<String, SecurityScheme> {} Ways to log in, like {'bearerAuth': SecurityScheme.bearer()}.
securityByMiddleware Map<String, List<Map<String, List<String>>>> {} Security for routes that use a middleware class with this name. It wins over @Security on the class. A class name that ends with AuthMiddleware gets bearerAuth when it has neither.
registry OpenApiRegistry OpenApiRegistry() (empty) What dox_builder found in the code. Pass openApiRegistry from lib/generated/openapi.g.dart.
ui DocsUi DocsUi.scalar scalar or swagger.
scalar ScalarOptions ScalarOptions() Options of the Scalar page. See below.
pageTitle String? null (uses info.title) Title of the /docs page.
include List<String> [] (all routes) Only routes with these paths are in the docs, like ['/api/*']. A * at the end matches the rest of the path.
exclude List<String> [] Routes with these paths are left out. Checked after include.

ScalarOptions (lib/src/docs_ui.dart in dartondox/dox-openapi):

Field Type Default Meaning
theme ScalarTheme ScalarTheme.default_ One of default_, alternate, moon, purple, solarized, bluePlanet, deepSpace, saturn, kepler, elysiajs, fastify, mars, laserwave, none.
darkMode bool false Start in dark mode.
showDownloadButton bool true Show the download button for the OpenAPI document.
proxyUrl String? null Send "Try it" requests through this proxy.

SocketIoConfig

SocketIoProvider of the dox_socketio package takes it. See Socket.IO. Source: lib/src/dox/socket_io_config.dart in dartondox/dox-socketio.

Field Type Default Meaning
enabled bool true Mount Socket.IO on the HTTP port at /socket.io/.
options ServerOptions ServerOptions() Engine options. See below.
namespaces List<NamespaceHandler> [] Namespaces to register, like ChatNamespace().
adapter SocketAdapterFactory? null (in memory with one isolate, IsolateAdapter with many) Makes the adapter in each isolate. Use a Redis adapter with many servers.

ServerOptions (lib/src/engine/server_options.dart in dox-socketio). The defaults match the Node.js server.

Field Type Default Meaning
path String /socket.io/ URL path. Must end with /.
pingInterval Duration 25 s Time between two server pings.
pingTimeout Duration 20 s Time to wait for a pong before the session is closed.
upgradeTimeout Duration 10 s Time a websocket upgrade may take.
connectTimeout Duration 45 s Time a client has to join a namespace after the handshake.
maxHttpBufferSize int 1000000 Biggest message in bytes a client may send.
maxAttachments int 10 Most binary attachments in one packet. A packet with more closes that client.
transports List<String> ['polling', 'websocket'] Allowed transports.
allowUpgrades bool true Allow upgrades from polling to websocket.
cors CorsOptions? null (no CORS headers) CORS for the long-polling requests.

CorsOptions:

Field Type Default Meaning
origins List<String> ['*'] Allowed origins.
credentials bool false Send Access-Control-Allow-Credentials: true.
methods List<String> ['GET', 'POST'] Allowed methods for preflight.
allowedHeaders List<String>? null (the requested headers) Allowed request headers.
maxAge Duration? null How long a browser may cache the preflight answer.

DatabaseConfig

The database is not a field of AppConfig. A provider calls SqlQueryBuilder.initializeWithDatabaseConfig(databaseConfig) in its setup(). Source: packages/dox-orm/lib/src/types/database_config.dart and connection_config.dart in dartondox/dox-orm.

Field Type Default Meaning
connection String required Name of the connection to use. A missing name throws Exception('<name> not found').
connections Map<String, ConnectionConfig> required Connection name to config.

ConnectionConfig:

Field Type Default Meaning
driver Driver required Driver.postgres, Driver.mysql (also MariaDB) or Driver.sqlite.
host String 'localhost' Database host. Not used by sqlite.
port int 0 Database port. Not used by sqlite.
user String '' Database user. Not used by sqlite.
password String '' Database password. Not used by sqlite.
database String required Database name. For sqlite: the file path, or :memory:.
useSSL bool false Use TLS. Postgres: mode require (no certificate check), set extra['sslMode'] to change it. MySQL: the certificate is checked.
debug bool required Print every query with printer.
printer QueryPrinter? null ConsoleQueryPrinter(), PrettyQueryPrinter(), FileQueryPrinter(file: File('queries.log')) or your own. FileQueryPrinter(file: ..., buffered: true) writes in the background, so a query does not wait for the disk. Then call await printer.flush() before exit(), or the last lines are lost.
logRedact List<String> [] Names of values to hide in the query log. A value shows as *** when its key ends with one of these names, in any case. ['password', 'token'] hides password, users.password and remember_token. Only the log changes. The query gets the real values. The list of the default connection counts for every query. The list of a named connection counts too, for the queries on that connection.
extra Map<String, dynamic> {} Driver options. See below.
driverFactory DBDriver Function(ConnectionConfig)? null Your own driver class. It wins over every other setting.

Keys of extra:

Driver Key Type Default Meaning
postgres, mysql maxConnectionCount int 10 Most open connections, for the whole process.
postgres, mysql threads int 1 Rust threads of the native driver. Only the first pool sets it.
mysql, sqlite preparedStatementCacheSize int 100 Prepared statements kept per connection.
postgres sslMode String require with useSSL, else disable TLS mode: disable, prefer, require or verify-full.
postgres sslRootCert String none Path of a PEM file with the CA certificates to trust for verify-full. sslrootcert in DATABASE_URL.
postgres sslWarning bool true false hides the warning that Dox prints (once per isolate) when TLS mode is require. sslWarning=false in DATABASE_URL works too.
postgres timeZone String UTC Session time zone.
postgres applicationName String none Name of the app in pg_stat_activity.
mysql verifyCertificate bool true false skips the TLS certificate check. Only for a self-signed certificate in development.
mysql maxConnectionAge Duration 12 hours Close and reopen a connection after this time.
sqlite busyTimeout int 5000 PRAGMA busy_timeout in milliseconds.

The database.dart of a new project also sets maxConnectionAge for Postgres and collation for MySQL. The Postgres driver does not read maxConnectionAge, and no driver reads collation. So these two keys change nothing.

AuthConfig

Auth is not a field of AppConfig. A provider calls Auth.initialize(AuthConfig(...)) in its setup(). Source: lib/src/interfaces.dart in dartondox/dox-auth.

Class Field Type Default Meaning
AuthConfig defaultGuard String required The guard Auth() uses when no guard is named.
AuthConfig guards Map<String, AuthGuard> {} Guard name to guard.
AuthGuard driver AuthDriver required How a token is made and checked, like JwtAuthDriver(secret: SecretKey(...)).
AuthGuard provider AuthProvider required Where users come from.
AuthProvider model dynamic Function() required Makes the user model, like () => User().
AuthProvider identifierFields List<String> ['email'] Columns attempt() matches the login with.
AuthProvider passwordField String 'password' Column with the bcrypt hash.

Full example

The config files of a new project. They read their values from env, the typed env class in lib/config/env.dart (see Env reference).

lib/config/app.dart
import 'dart:io';

import 'package:dox_core/dox_core.dart';
import 'package:my_app/config/cache.dart';
import 'package:my_app/config/cors.dart';
import 'package:my_app/config/logger.dart';
import 'package:my_app/config/env.dart';
import 'package:my_app/generated/container.g.dart';

AppConfig appConfig = AppConfig(
  /// Changing the key makes old cookies and encrypted data unreadable.
  appKey: env.appKey,
  serverPort: env.appPort,
  totalIsolate: env.appTotalIsolate ?? Platform.numberOfProcessors,
  globalMiddleware: <dynamic>[
    LogMiddleware(enabled: env.appEnv != 'production'),
  ],
  container: registerContainer,
  cache: cache,
  cors: cors,
  logger: logger,
);
lib/config/cache.dart
import 'package:dox_core/dox_core.dart';
import 'package:my_app/config/env.dart';

CacheConfig cache = CacheConfig(
  defaultStore: env.cacheStore,
  stores: <String, Map<String, dynamic>>{
    'file': <String, dynamic>{'driver': 'file', 'path': 'storage/cache'},

    /// one map per isolate, fast, not shared
    'memory': <String, dynamic>{'driver': 'memory', 'max_size': 10000},
  },
);
lib/config/logger.dart
import 'package:dox_core/dox_core.dart';
import 'package:my_app/config/env.dart';

LoggerConfig logger = LoggerConfig(
  name: env.appName,
  enabled: true,
  level: env.logLevel,
  /// colored text is slow. JSON lines in production.
  prettyPrint: env.isDevelopment,
);
lib/config/database.dart
import 'package:dox_orm/dox_orm.dart';
import 'package:my_app/config/env.dart';

/// Print every SQL query only in development.
bool _debug = env.isDevelopment;

DatabaseConfig databaseConfig = DatabaseConfig(
  connection: env.dbConnection,
  connections: <String, ConnectionConfig>{
    'postgres': ConnectionConfig(
      driver: Driver.postgres,
      host: env.dbHost,
      port: env.dbPort ?? 5432,
      user: env.dbUsername,
      password: env.dbPassword,
      database: env.dbName,
      extra: <String, dynamic>{
        /// One pool for all isolates.
        'maxConnectionCount': 10,
        'maxConnectionAge': Duration(hours: 1),
      },
      debug: _debug,
      printer: PrettyQueryPrinter(),
    ),

    /// MySQL and MariaDB
    'mysql': ConnectionConfig(
      driver: Driver.mysql,
      host: env.dbHost,
      port: env.dbPort ?? 3306,
      user: env.dbUsername,
      password: env.dbPassword,
      database: env.dbName,
      extra: <String, dynamic>{'collation': 'utf8mb4_general_ci'},
      debug: _debug,
      printer: PrettyQueryPrinter(),
    ),

    /// `DB_NAME` is a file path, or `:memory:`.
    'sqlite': ConnectionConfig(
      driver: Driver.sqlite,
      database: env.dbName,
      debug: _debug,
      printer: PrettyQueryPrinter(),
    ),
  },
);
lib/config/cors.dart
import 'package:dox_core/dox_core.dart';

CORSConfig cors = CORSConfig(
  enabled: false,
  // a list: Dox sends back the request origin only when it is in the list
  origin: <String>['http://localhost:3000'],
  methods: <String>['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'],
  headers: <String>[
    'accept',
    'authorization',
    'content-type',
    'x-csrf-token',
    'x-xsrf-token',
    'x-requested-with',
  ],
  exposeHeaders: <String>[
    'cache-control',
    'content-language',
    'content-type',
    'expires',
    'last-modified',
    'pragma',
  ],
  credentials: true,
  maxAge: 90,
);

Do not use origin: '*' together with credentials: true. With credentials the browser sends cookies, so it does not accept *, and the call fails. Dox does not send back any origin in place of *, because that would let every site call the app with the user's cookies. '*' is fine for a public API with credentials: false (or not set).

lib/providers/orm_provider.dart
import 'package:dox_core/dox_core.dart';
import 'package:dox_orm/dox_orm.dart';
import 'package:my_app/config/database.dart';

/// Dox finds it by itself and runs it in every isolate.
/// No database? Delete this file.
class ORMProvider extends DoxProvider {
  @override
  Future<void> setup() async {
    SqlQueryBuilder.initializeWithDatabaseConfig(databaseConfig);
  }

  @override
  Future<void> shutdown() async {
    await SqlQueryBuilder.close();
  }
}

A new project also has lib/config/storage.dart, queue.dart and schedule.dart, with a provider for each in lib/providers/. See File storage, Queue and Scheduler.

A new project has no openapi.dart, socketio.dart or auth provider. You add them when you need them. See OpenAPI, Socket.IO and Authentication.