Knowledge Base
ConfigurationPluginsSettingsEnvironment VariablesFAB StructurePlugin Runtime RespondersThe ResponderThe request_context objectDirectivesProductionRuntime EnvironmentUnderstanding Assets

Plugin Runtime Responders

Most of the time, if you're looking into customising the server-side functionality of a FAB, you want to introduce a file with a runtime function that sets up a Responder. The simple case looks like this:

export function runtime(args, metadata) {
return async function responder(request_context) {
return new Response('HI', {
status: 200,

The runtime function is synchronous, and receives two parameters:

  • Any args, passed in from the fab.config.json5. Given the following config:
plugins: {
'./src/fab-server.js': {
some: 'argument'

the args argument to render would be {"some": "argument"}. Normal value conversion rules apply.

  • The metadata object, that's generated by the build stages of the plugins. Unless you're writing your own build stage, you probably won't need anything from here.

This only executes once, when the FAB is initialised, so it can be a good place to set up any data structures/helpers that you'll need for the responder later.

The Responder

The return value of the runtime function is a Responder:

export function runtime(args, metadata) {
return async function responder(request_context) {
const { url } = request_context
if (url.pathname === '/not-my-problem') {
return undefined
if (url.pathname.startsWith('/old-urls')) {
return new Response('Redirecting...', {
status: 302,
headers: {
Location: url.pathname.replace(/old-urls/, 'new-urls'),
if (url.pathname.startsWith('/api')) {
return new Request(`https://example.backend${url.pathname}`)
if (url.pathname === '/favicon.ico') {
const response = await fetch('/_assets/favicon.a1b2c3d4f3.ico')
response.headers.set('cache-control', 'no-cache')
return response
// could do an api on top like
// return await FAB.fetchNoCache('/_assets/favicon.a1b2c3d4f3.ico')
// but probably not worth it, is it?

Things to note:

  • The responder is async, and the FAB runtime will wait for each responder in turn. So always check that you're interested in a particular request before doing anything expensive
  • You can return undefined to skip this responder, or a Response (either constructed by hand or from a fetch request), or a Directive for more advanced behaviours.

The request_context object

Currently it is { request, settings, url }, but that's in flux.


WIP, still figuring this out.