Plugin options
The forms plugin is configured with registration options
Options
| Option | Required | Description |
|---|---|---|
nunjucks | Yes | Template engine configuration. See Nunjucks configuration |
viewContext | Yes | A function that provides global context to all templates. See viewContext |
baseUrl | Yes | Base URL of the application (protocol and hostname, e.g. "https://myservice.gov.uk"). Used for generating absolute URLs in markdown rendering and other contexts |
model | No | Pre-built FormModel instance. When provided, the plugin serves a single static form definition. When omitted, forms are loaded dynamically via formsService. See model |
services | No | Object containing formsService, formSubmissionService, and outputService. See services |
controllers | No | Object map of custom page controllers used to override the default. See custom controllers |
globals | No | A map of custom template globals to include. See custom globals |
filters | No | A map of custom template filters to include. See custom filters |
cache | No | Caching options. Recommended for production — either a cache name string or a custom CacheService instance. See custom cache |
pluginPath | No | The location of the plugin. Defaults to node_modules/@defra/forms-engine-plugin |
preparePageEventRequestOptions | No | A function invoked for HTTP-based page events to customise outbound request options |
saveAndExit | No | Configuration for custom session management. See save and exit |
onRequest | No | A function invoked on each request to any form route (e.g. /{slug}/{path}). See onRequest |
ordnanceSurveyApiKey | No | Ordnance Survey API key. Required to enable the inline map on geospatial components. See geospatial map |
ordnanceSurveyApiSecret | No | Ordnance Survey API secret. Required alongside ordnanceSurveyApiKey to enable the inline map on geospatial components |
Option details
Services
See our services documentation.
Custom controllers
The controllers option lets you register custom page controller classes. A custom controller is tied to a page in your form definition by setting the page's controller property to the key you register it under.
See Custom page controllers for a full guide including examples and a reference of overridable members.
Nunjucks configuration
The nunjucks option is required and configures the template engine paths and layout.
{ baseLayoutPath: string // Path to the base layout template paths: string[] // Array of paths to search for Nunjucks templates}Example:
await server.register({ plugin, options: { nunjucks: { baseLayoutPath: 'layout.html', paths: [ 'src/server/views', 'node_modules/govuk-frontend/dist' ] } }})The baseLayoutPath is the file that all form pages will extend. The paths array tells Nunjucks where to look for templates, including your custom templates and any third-party template libraries (like GOV.UK Frontend).
viewContext
The viewContext option is a required function that provides global context variables to all templates rendered by the plugin.
type ViewContext = ( request: AnyFormRequest | null) => Record<string, unknown> | Promise<Record<string, unknown>>This function receives the current request (or null for non-request contexts) and should return an object containing any data you want available in your templates, such as:
- Application version
- Asset paths
- Configuration values
- CSRF tokens
- User session data
- Feature flags
Example:
import pkg from './package.json' with { type: 'json' }
await server.register({ plugin, options: { viewContext: (request) => { return { appVersion: pkg.version, assetPath: '/assets', config: { serviceName: 'My Service', phaseTag: 'beta' }, // Add CSRF token if request exists crumb: request?.plugins.crumb?.generate?.(request) } } }})The context returned by this function is merged with the plugin's internal context and made available to all templates.
model
The model option allows you to provide a pre-built FormModel instance to serve a single static form definition.
When model is provided:
- The plugin serves only that specific form
- No dynamic form loading occurs
- Useful for testing or single-form applications
When model is omitted (recommended for production):
- Forms are loaded dynamically via
formsService - Multiple forms can be served
- Form definitions can be updated without redeploying
Example (single form):
import { FormModel } from '@defra/forms-engine-plugin/engine/models/FormModel.js'
const definition = await getFormDefinition()
const model = new FormModel( definition, { basePath: '/my-form' }, services)
await server.register({ plugin, options: { model, // ... other options }})Custom globals and filters
The globals and filters options extend the Nunjucks template environment with custom functions and transform filters, available in all form page templates.
See Template extensions for registration examples and the list of built-in filters.
Custom cache
The default in-memory cache is unsuitable for production. Pass a named hapi catbox cache string for most deployments, or a subclassed CacheService instance when you need to customise any part of the state storage lifecycle.
See Session cache for setup instructions.
onRequest
If provided, the onRequest plugin option will be invoked on each request to any routes registered by the plugin.
export type OnRequestCallback = ( request: AnyFormRequest, h: FormResponseToolkit, context: FormContext) => ResponseObject | FormResponseToolkit['continue'] | Promise<ResponseObject | FormResponseToolkit['continue']>Here's an example of how it could be used to secure access to forms:
await server.register({ plugin, options: { onRequest: async (request, h, context) => { const { auth } = request
// Check if user is authenticated if (!auth.isAuthenticated) { return h.redirect('/login').takeover() }
// Return h.continue to resume with normal form processing return h.continue } }})saveAndExit
The saveAndExit option adds a secondary button to question pages that lets users save their progress and return later. When clicked, the plugin calls your handler after validating the current page.
See Save and Exit for the full guide including the handler signature and examples.
Geospatial map
Geospatial components (Easting Northing, OS Grid Ref, National Grid Field Number, Lat Long, Geospatial) render an inline Ordnance Survey map alongside their input fields. The map lets users click a location to auto-populate the coordinate inputs, rather than typing values manually.
The map is only activated when both ordnanceSurveyApiKey and ordnanceSurveyApiSecret are provided at plugin registration. Without them the components still function as plain text inputs.
await server.register({ plugin, options: { ordnanceSurveyApiKey: process.env.ORDNANCE_SURVEY_API_KEY, ordnanceSurveyApiSecret: process.env.ORDNANCE_SURVEY_API_SECRET, // ... other options }})