App behavior options
bodyParser[Object]: Parameters to supply to the body-parser module which handles POST requests.urlEncoded[Object]: Parameters to supply to body-parser.urlencoded.json[Object]: Parameters to supply to body-parser.json.
Default: [Object]
{
urlEncoded: {
extended: true
},
json: {}
}csrfProtection[Boolean or Object]: Whether to enable Cross-Site Request Forgery protection. Roosevelt asks the browser where each request came from and refuses any request that changes data unless the browser says it came from your own site, which browsers report themselves and page scripts cannot forge. Default:true.- To disable the feature entirely, set it to false. To configure it, supply an object.
- In the object:
blockCrossSiteRequests[Boolean]: Whether to ask the browser where each request came from and refuse any request that changes data unless the browser says it came from your own site. Default:true.- Requests that arrive without the browser saying where they came from are also refused. Anything that is not a browser, such as a mobile app or another server, does not send that information, so add those routes to
exemptions. - This cannot stop an untrusted request coming from another subdomain of your own site, because browsers report those the same way they report your own pages. Use CSRF tokens via
requireTokensto add protection against untrusted subdomains. - Setting this param to
falseleaves your app protected only by whateverrequireTokensis set to.
- Requests that arrive without the browser saying where they came from are also refused. Anything that is not a browser, such as a mobile app or another server, does not send that information, so add those routes to
requireTokens[Boolean or String]: Whether requests that change data must carry a CSRF token. Default:false.false: no token is needed, which is fine for most apps. Note thatreq.csrfToken()is not available when set tofalse, since there are no tokens to generate.true: always require a token. Set totrueif anything untrusted is hosted on a subdomain you share, such as user uploaded content or a separate app someone else runs. That is the only way to stop an untrusted request coming from another subdomain of your own site, because browsers report those the same way they report your own pages. See the coding apps section for examples."whenHeaderMissing": require a token only from browsers too old to report where a request came from, since they are otherwise refused. This does not stop an untrusted request coming from another subdomain of your own site either, because browsers that do report where a request came from are trusted without a token.
trustedOrigins[Array of Strings]: Other sites you expect requests from, such as a payment provider posting back to your app. Default:[].- Example:
["https://accounts.someplace.somedomain"]. Matched against the request'sOriginheader. - This only helps callers that send an
Originheader, which means browsers. Useexemptionsfor anything else.
- Example:
exemptions[Array of Strings]: Routes to skip all of these checks on. Supports wildcard matching. Use this for routes called by anything that is not a browser, such as a mobile app or another server.
Example of exemptions list: [Object]
{
exemptions: [
'/foo',
'/bar',
'/baz'
]
}expressSession[Boolean or Object]: Parameters to pass to the express-session module. Default:true.
Default if expressSession is set to true: [Object]
{
secret, // an auto-generated secret, read from your secrets folder
resave: false, // usually a bad idea to set to true
saveUninitialized: false, // usually a bad idea to set to true
cookie: {
secure: 'auto', // marks the cookie HTTPS only on any request that reached your app over HTTPS, whether the app served it or a web server in front did
sameSite: 'strict', // adds same site enforcement
maxAge: 347126472000 // sets expiration very far in the future (~11 years) to basically never expire
},
store // the expressSessionStore.instance Roosevelt param
}If you supply your own config, note what cookie.sameSite does before leaving it out: Setting it to "strict" tells the browser not to send the session cookie along with any request that came from another site. A forged request from another site therefore arrives with nobody logged in, which is one of the protections that stops another site from making requests as your logged in users. Roosevelt warns at startup if your config leaves it unset, since a hand written config can drop it without meaning to.
It does not stop a request coming from another subdomain of your own site, because browsers count those as the same site. Only setting csrfProtection.requireTokens to true does that.
One side effect of "strict" is that a user following a link to your app from somewhere else, such as an email or a chat message, arrives without their session on that first page load and appears logged out. Reloading the page or clicking any link within your app restores it, since those requests come from your own site.
If that matters for your app, set cookie.sameSite to "lax" instead. The browser will then send the session cookie when a user navigates to your app from elsewhere, while still withholding it from a form or script on another site that tries to change data.
Whichever you choose, csrfProtection.blockCrossSiteRequests still refuses requests that change data unless the browser says they came from your own site, so relaxing this setting does not give up your CSRF protection.
Give users a new session when they log in. This applies to any app with logins, whichever session store it uses. A visitor usually has a session before they log in, from browsing your site. If your app logs them in by adding who they are to that same session, anyone who already knew its ID now has a logged-in session as that user. Someone could have learned or set the ID beforehand, for example on a shared computer, or by planting a cookie from another subdomain of your site. This is called session fixation. To prevent it, call req.session.regenerate() when a user logs in, which replaces their session with a new one under a new ID, and put who they are in the new one:
req.session.regenerate(err => {
if (err) return next(err)
req.session.userId = user.id
req.session.save(err => err ? next(err) : res.redirect('/'))
})expressSessionStore[Object]: Define a custom session store to use withexpress-sessioninstead of the default one provided by Roosevelt. Roosevelt's default store keeps sessions in a file on the server running the app, so you need this if you run your app on more than one server. See storing sessions somewhere every server can reach.filename[String]: Name of the session file.instance: [Object] A store instance. See this list for compatible stores.preset[String]: Available presets provided by Roosevelt. Only used ifinstanceis not provided.Available options:
"default": Use Roosevelt's default session store, which keeps sessions in a SQLite file on the server the app runs on, named byfilename. It began as a hard fork of better-sqlite3-session-store, which is no longer maintained, and now shares its code with thepostgres,mysql, andmariadbpresets below, so each of them expires sessions the same way."postgres": Keep sessions in PostgreSQL. They are kept in the database given aspresetOptions.client, or inapp.get('db')if you set one in theonBeforeMiddlewareevent. They are kept in asessionstable Roosevelt makes the first time it is used. The database can be anything with aquery(sql, params)method, such as a pgPool.- Example, with a pool of its own:
expressSessionStore: { preset: 'postgres', presetOptions: { client: new (require('pg').Pool)({ connectionString: process.env.DATABASE_URL }) // a pool does not connect until it is first used } }- Example, with your app's own database, set in `onBeforeMiddleware`, and closed in `onAppExit`:expressSessionStore: { preset: 'postgres' }, onBeforeMiddleware: async app => app.set('db', await connectToMyDatabase()), onAppExit: app => app.get('db').end()- `"mysql"`: Keep sessions in MySQL, the same way as the `postgres` preset. The database can be anything with a `query(sql, params)` method, such as a [mysql2](https://sidorares.github.io/node-mysql2/) pool or a [mariadb](https://github.com/mariadb-corporation/mariadb-connector-nodejs) pool, whichever way it hands back its results. - `"mariadb"`: The same as `"mysql"`, for MariaDB. It clears out expired sessions and ones past `maxInactivity` the same way as the default store. - `"express-session-default"`: Use `express-session`'s own default store, which keeps sessions in memory. Not recommended: every session is lost when the process restarts, so a deploy signs everyone out, and memory use grows without bound. `express-session` itself advises against it outside development.presetOptions[Object]: Options to pass to the preset session store if one is selected. Only used ifinstanceis not provided.checkPeriod[Number]: How often, in milliseconds, Roosevelt clears sessions that have gone pastmaxInactivityout of the session store.client[Object]: For thepostgres,mysql, andmariadbpresets, the database to keep sessions in: anything with aquery(sql, params)method, such as a connection pool from pg, mysql2, or mariadb. Without it, the preset usesapp.get('db'), if your app sets it in itsonBeforeMiddlewareevent.table[String]: For thepostgres,mysql, andmariadbpresets, the table to keep sessions in. Default:"sessions".
Either
instanceorpresetmust be set for this param to work properly.maxInactivity[Number]: How long, in milliseconds, a session may go unused before Roosevelt deletes it from the session store. Default:7889238000(about 3 months). Only applies to Roosevelt's default session store.- This is separate from
expressSession.cookie.maxAge, which decides how long a user stays logged in. Roosevelt sets that very far in the future by default so that active users are never logged out, which would otherwise mean abandoned sessions sat in the session store for just as long.maxInactivitylets you keep long-lived logins while still clearing out sessions nobody has come back to. - The clock resets every time a session is used, so a session belonging to an active user is never deleted no matter how old it is.
- Sessions are swept on the interval set by
presetOptions.checkPeriod. When a browser turns up with a cookie for a session that has since been deleted, Roosevelt clears that cookie so it does not linger until its own far off expiry. - If you prefer or your app depends on sessions pretty much never expiring, set this to
347126472000(about 11 years) to match theexpressSession.cookie.maxAgedefault.
- This is separate from
Default: [Object]
{
filename: 'sessions.sqlite',
instance: null,
preset: 'default',
presetOptions: {
checkPeriod: 86400000 // one day
},
maxInactivity: 7889238000 // three months
}formidable: Parameters to pass to formidable using formidable's API for multipart form processing (file uploads). Access files uploaded in your controllers by examining thereq.filesobject. Roosevelt will remove any files uploaded to the upload directory when the request ends automatically. To keep any, be sure to move them before the request ends.
Default: [Object]
{
multiples: true // enables multiple files to be uploaded simultaneously
}To disable multipart forms entirely, set formidable to false.
helmet[Object]: Parameters to pass to the helmet module. This module helps secure Express apps by setting HTTP response headers.- The default options are specified in the helmet docs, with the following exceptions that Roosevelt makes to the default
Content-Security-Policysettings:- The
upgrade-insecure-requestsdirective has been removed. This change prevents this bug. - The
script-srcdirective has been set to"unsafe-inline". This makes it possible to use inline scripts. - The
form-actiondirective has been set tonull. This makes it possible to submit forms to other domains. - You can reverse any of these changes by configuring helmet yourself.
- The
- To disable helmet entirely, set the param to
false.
- The default options are specified in the helmet docs, with the following exceptions that Roosevelt makes to the default
logging: Parameters to pass to roosevelt-logger. See roosevelt-logger parameters documentation for configuration options.
Default: [Object]
{
quieterStartup: false,
methods: {
http: true,
info: true,
warn: true,
error: true,
verbose: false
}
}logging.quieterStartup[Boolean]: Show notices that repeat on every start at most once a day instead of every time. Default:false.- Some notices simply restate how the app is configured, such as which folder is being hosted or that build artifacts are switched off. Nothing is wrong, so seeing them on every restart while developing gets noisy.
- Only those repeating notices are held back. Anything reporting an actual problem, such as a missing favicon or a file that failed to compile, always prints.
- Roosevelt remembers which notices it has shown in your system's temp directory, so restarting the app does not bring them all back. Rebooting, or waiting a day, does.
- Can also be set with the
--quieter-startupor-qcommand line flags, or theQUIETER_STARTUPenvironment variable.
makeBuildArtifacts[Boolean or String]: When enabled Roosevelt will generate user-specified directories, CSS/JS bundles, etc.- Defaults to
falsefor apps created manually. - Will be set to
truein apps generated with the app generator. - Can also accept a value of
"staticsOnly"which will allow Roosevelt to create static files but skip the creation of the MVC directories.
- Defaults to
buildOnly[Boolean]: When enabledstartServerbuilds the app and stops there rather than listening for requests. Use it for a build step in CI or a deploy, which has to finish and exit rather than sit on a port. Default:false.- Set by the
--buildand-bcommand line flags, which also setmakeBuildArtifactsto"staticsOnly". - Calling
initServer(init) instead ofstartServerhas the same effect, and is the better fit when your build script drives Roosevelt directly rather than being handed command line flags.
- Set by the
incrementalBuilds[Boolean]: When enabled Roosevelt will skip regenerating a static file if none of the source files it was built from have changed since the last build. This applies to files declared in thecopyparam too, which are left alone when neither the source nor the copy has changed. Default:true.- Set to
falseto disable the feature and rebuild everything on every start. Deleting yourbuildFolderhas the same one-time effect.
- Set to
routePrefix[String]: A prefix prepended to your application's routes. Applies to all routes and static files. Default:null.- Example: When set to
"foo"a route bound to/will be instead be bound to/foo/. - This prefix is exposed via the
routePrefixExpress variable which should be used for resolving the absolute paths to statics programmatically.- Example: An image located at
/images/teddy.jpgcan be resolved in a prefix-agnostic way via${app.get('routePrefix')}/images/teddy.jpg.
- Example: An image located at
- Example: When set to
sitemap[Object]: Serve a sitemap that lists your site's pages for search engines, and arobots.txtthat points them to it.enable[Boolean]: Whether to serve the sitemap. Default:false.baseUrl[String]: The address your site is served at, which the paths in the sitemap are added to, since a sitemap has to list full URLs. When it is not set, the address the sitemap was requested at is used. Default:null.path[String]: Where the sitemap is served. Default:"/sitemap.xml".staticPages[Boolean]: List the pages built by the static page generator automatically, at the URLs it writes them to. Default:true.routesFile[String]: The file that says which of your app's routes the sitemap will list. Generated automatically in development mode. Set any route you want exposed to true, and any you want kept out of both the sitemap and search results to false (seenoindexExcluded). Review the contents to ensure nothing sensitive is exposed and commit this file to your repo. Default:"sitemap-routes.json".- Example:
json { "/": true, "/about": true, "/account": false, "/admin/**": false } - Keys can be patterns:
*matches one part of a path and**matches any number of them, so"/admin/**"covers everything under/admin, while"/admin/*"would miss/admin/users/new.
- Example:
noindexExcluded[Boolean]: Tell search engines not to list the pages at routes the routes file marksfalse, such as/accountor/admin/**, by sending them with anX-Robots-Tag: noindexheader, so that a route left out of the sitemap is also kept out of search results. A route markedfalseis always one someone decided on, since a route nobody has reviewed yet isnull, and gets no header. To leave a route out of the sitemap without keeping it out of search results, set this tofalse. A controller can also send anX-Robots-Tagheader of its own, which replaces this one. Default:true.urls[Function]: A function that returns more URLs to list, for pages your app makes itself thatroutesFilecannot cover, such as the pages behind a route with parameters, built from a database. Default:null.- Example:
urls: async app => (await getArticles()).map(article => ({ loc: article.route, lastmod: article.updated })) - Each URL can be a path or a full URL, or an object with a
locand alastmod. Give alastmodonly when you know when the page last changed, since search engines stop trusting one that is always the time the sitemap was made. An object can also have achangefreqand apriority, but Google ignores both, so there is little point. - Code that is not in your config file, such as a controller, can add URLs the same way with the
sitemapExpress variable.
- Example:
exclude[Array of Strings]: Paths to leave out of the sitemap wherever they come from, which may use wildcards, such as["/drafts/*"]. The routes file already decides for your routes, so this is for static pages and for URLs fromurlsandadd(). Default:[].cacheSeconds[Number]: How long to keep the sitemap before making it again. Callapp.get('sitemap').refresh()to make it again sooner, such as after adding a page. Default:null, which is an hour in production mode and every request in development mode.robotsTxt[Boolean or String]: Serve arobots.txtthat points to the sitemap. Whentrue, it allows everything. When a path to a file, relative to your app's folder, such as"mvc/views/robots.txt", it is that file, with the line pointing to the sitemap added unless the file has it already. It is read on every request, so edits to it show up straight away. An app with arobots.txtroute or public file of its own keeps it, and can add the line pointing to the sitemap withapp.get('sitemap').robotsLine(). Default:true.file[Boolean]: Also write the sitemap, and therobots.txtabove, into the public folder when the app builds, for a static site whose web server serves its files without Roosevelt. Default:false.- A sitemap only helps when the pages it lists agree with it: each should load without a redirect, not ask to be kept out of search results, and not name another page as its canonical URL.
- A page's canonical URL is the one address search engines should list it at. The same page can often be reached at more than one address, such as with a query string or without one, over
httporhttps, or with a trailing slash or without one, and search engines treat each address as a page of its own unless the page says which one it is. It says so with a<link rel="canonical" href="https://example.com/page">tag in its<head>, and search engines then list that address, and count links to the others as links to it. A sitemap that lists a different address than the one a page names as canonical is contradicting it, and search engines may ignore the sitemap's URL.
- A page's canonical URL is the one address search engines should list it at. The same page can often be reached at more than one address, such as with a query string or without one, over
- The
sitemapExpress variable has two methods to keep the pages and the sitemap agreeing:app.get('sitemap').canonical(req, loc)makes a page's canonical URL for the<link rel="canonical">tag.app.get('sitemap').verify(options)can be used to verify the sitemap is well-formed in automated tests. It requests every URL the sitemap lists and resolves to{ checked, problems }, where each problem is a{ loc, problem }for a URL that does not load, redirects, says not to list it, or names another page as canonical.options.originis where to request them from instead of the address they are listed at, such as"http://localhost:8080".options.requestis a function of your own for making each request, which is given the URL and returns{ status, headers, body }.options.rejectUnauthorizedcan be set tofalseto accept a certificate made for testing.options.concurrencyis how many requests to make at once, which is 10 by default.
viewEngine[String]: What templating engine to use, formatted as"fileExtension: nodeModule".- Defaults to
"none"for apps created manually. - Will be set to
"html: teddy"in apps generated with the app generator. - Also by default when using the app generator, the teddy module is marked as a dependency in
package.json. - To use multiple templating systems, supply an array of engines to use in the same string format. Each engine you use must also be marked as a dependency in your app's
package.json. Whichever engine you supply first with this parameter will be considered the default.
- Defaults to
Example configuration using multiple templating systems: [Object]
{
viewEngine: [
'html: teddy',
'php: php',
'ejs: ejs'
]
}