Configuration
Primate works out of the box with zero configuration. In some cases, you may wish to change the defaults. The most common use case is activating additional modules.
Configuration files are located in config. Anything you configure is merged
into the defaults.
app.ts
import config from "primate/config";
export default config({
/* options */
});import config from "primate/config";
export default config({
/* options */
});config/app.ts exports the application facade for your app. For using that
value at runtime — including app.config(), app.env(), app.view(), and
app.root — see the Application page.
App options
| Option | Default | Description |
|---|---|---|
| client.groups | undefined |
isolated client bundle groups |
| client.routes | undefined |
route-prefix to bundle-group mapping |
| db.migrations | undefined |
database migration configuration |
| entrypoints | {} |
named client entrypoints |
| http.csp | {} |
content security policy |
| http.headers | {} |
default HTTP response headers |
| http.host | "localhost" |
server host |
| http.port | 6161 |
server port |
| http.ssl.cert | undefined |
path to SSL certificate |
| http.ssl.key | undefined |
path to SSL private key |
| http.static.root | "/" |
web path of static assets |
| loaders | {} |
esbuild file loaders by extension |
| env.schema | undefined |
schema for typed environment variables |
| modules | [] |
extension modules |
| i18n.defaultLocale | undefined |
default locale |
| i18n.locales | [] |
list of locales |
| i18n.currency | "USD" |
active currency |
| i18n.persist | "cookie" |
locale persistence mode |
db.migrations
Configuration for Primate's opt-in migration system.
import config from "primate/config";
import db from "@/config/db";
export default config({
db: {
migrations: {
table: "migration",
db,
},
},
});Apply migrations explicitly with primate migrate:apply during development or
build/migrate.js apply before starting a production server. The legacy
autoapply option is deprecated in 0.41 and will be removed in 0.42. See the
Stores page for the complete migration workflow.
client.groups
Client groups partition browser code and assets by URL route prefix. Each group is an independent build branch, compiled into its own output file tree. Shared dependencies are duplicated rather than emitted as chunks shared across an access boundary.
import config from "primate/config";
export default config({
client: {
groups: {
public: "/",
admin: "/admin/app/",
},
routes: {
"/": "public",
"/admin": "admin",
},
},
});client.groups maps group names to asset URL prefixes. client.routes maps URL
path prefixes to those names; values that are not keys in client.groups are
rejected. The longest matching route prefix wins, and prefixes match
whole path segments: /admin includes /admin/users but not /administrator.
A / assignment is required as the default and is checked during startup.
Mappings to unknown groups, duplicate normalized mappings, and duplicate asset
prefixes are also rejected during startup.
Each group receives its own bootstrap, route-page registry, CSS, dynamic
imports, and file-loader assets beneath its configured asset prefix. Top-level
files in views are shared deliberately and are duplicated into every group;
put group-private pages and layouts beside their handlers in routes.
Imported fonts, images, and other file-loader assets are likewise emitted under
each group's prefix, even when their contents are identical. Distinct URLs are
part of the isolation guarantee. Assets that are deliberately public and shared
across every authorization boundary can instead live in static.
Navigation within a group keeps normal client routing. Navigation across groups stays in the same document: Primate first loads the destination assets and inactive styles and waits for its frontend to become ready. It then disposes the active frontend instance, replaces its group styles, and mounts the destination. Links, form redirects, and browser history all use this transition. If a destination asset cannot be loaded or is rejected by the proxy, the active app, URL, and styles remain in place. Static module code may remain in the browser's module cache after disposal.
This allows a reverse proxy to apply the same authentication rule to both the
HTML route and its complete client file tree. For example, protect /admin and
/admin/app/, with the more specific asset rule evaluated before a catch-all
public rule. Production filenames are content-hashed and can be cached as
immutable assets; HTML should not be cached with the same policy.
Client groups provide asset isolation, not application authorization. Continue to authorize every protected request in route hooks or handlers. Source maps are not emitted by Primate's client production build.
entrypoints
Named client entrypoints bundled from the client directory and injected into
templates/app.html as placeholders.
import config from "primate/config";
export default config({
entrypoints: {
css: "master.css",
colorscheme: "colorscheme.ts",
},
});Each key becomes a placeholder in your HTML template. For a key css, add
%css% wherever you want the asset injected:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
%css% %head%
</head>
<body>
%body%
</body>
</html>Any file type supported by your active frontend modules works as an entrypoint
— if you have @primate/svelte configured, you can point an entrypoint at a
.svelte file and it will be bundled and injected like any other asset.
The names app, head, and body are reserved and cannot be used as
entrypoint keys.
http.csp
The Content Security Policy (CSP) to use.
Example of a restrictive policy.
{
// all content must come from own origin, excluding subdomains
"default-src": ["'self'"],
// styles must come from own origin, excluding subdomains
"style-src": ["'self'"],
// disallow <object>, <embed> and <applet> elements
"object-src": ["'none'"],
// disallow embedding
"frame-ancestors": ["'none'"],
// all form submissions must be to own origin
"form-action": ["'self'"],
// allow only own origin in <base>
"base-uri": ["'self'"],
}
http.headers
HTTP headers to use when generating requests using the view handler.
http.host
The HTTP host to use. This value is directly passed to the runtime.
http.port
The HTTP port to use. This value is directly passed to the runtime.
http.ssl.cert
Path to SSL certificate. If this property and http.ssl.key are set and
point to a valid key/certificate pair, Primate uses https instead of http.
http.ssl.key
Path to SSL key. If http.ssl.cert and this property are set and point to a
valid key/certificate pair, Primate uses https instead of http.
http.static.root
The path at which to serve static assets (those located in the static
directory). Static assets take precedence over routes. This option allows you
to have all static assets served at a subpath, like /public.
loaders
A map of file extensions to esbuild loaders. Currently only "file" is
supported, which copies the asset into the build output and replaces the import
with its URL — useful for fonts and other binary assets referenced from CSS.
import config from "primate/config";
export default config({
loaders: {
".woff2": "file",
},
});
env.schema
A Pema object schema used to validate and type environment variables exposed through the application facade.
import config from "primate/config";
import p from "pema";
export default config({
env: {
schema: p({
API_TOKEN: p.string,
PORT: p.u16,
}),
},
});With env.schema configured, app.env(key) validates values when the app
starts serving and becomes type-aware. See the Application page for usage.
modules
Additional modules to load at runtime.
i18n.defaultLocale
The default locale to use, must be one from the locales list.
i18n.locales
List of locales to use, must have at least one locale.
i18n.currency
Currency to use in localization.
i18n.persist
Locale persistence mode.
Reference
import type { Module } from "@primate/core";
import type { FileRef } from "@rcompat/fs";
interface Config {
http?: {
csp?: Record<string, string>;
headers?: Record<string, string>;
host?: string; // "localhost"
port?: number; // 6161
ssl?: {
cert?: FileRef | string;
key?: FileRef | string;
};
static?: {
root?: string; // "/"
};
};
modules?: Module[];
}
session.ts
import session from "primate/session";
export default session/*<SessionShape>*/({
/* options */
});import session from "primate/session";
export default session({
/* options */
});Session options
| Option | Default | Description |
|---|---|---|
| cookie.httpOnly | true |
mark cookie as HttpOnly |
| cookie.maxAge | none | persist cookie for this many seconds |
| cookie.name | "session_id" |
name of the session cookie |
| cookie.path | "/" |
path for which the cookie is valid |
| cookie.sameSite | "Lax" |
SameSite cookie policy |
| cookie.secure | app TLS setting | mark cookie as Secure |
| store | default in-memory store | store managing sessions |
cookie.httpOnly
Whether the session cookie should be marked HttpOnly and hidden from
client-side JavaScript.
cookie.maxAge
The number of seconds for which the browser should retain the session cookie. When omitted, it is removed when the browser session ends.
cookie.name
The name of the session cookie.
cookie.path
The session cookie path (paths on which the cookie is loaded).
cookie.sameSite
The level of security to use in sending the session cookies when browsing between websites.
cookie.secure
Whether the session cookie should be marked Secure. By default, this follows
the app's TLS setting. Set it explicitly when TLS terminates at a trusted reverse
proxy.
store
The store used to validate and persist sessions. By default, Primate uses an in-memory store that resets when the app restarts.
db/*.ts
import sqlite from "@primate/sqlite";
export default sqlite();import sqlite from "@primate/sqlite";
export default sqlite();