Skip to main content
Complete API reference for @forestadmin/agent (Node.js/TypeScript).

Agent Class

createAgent(options)

Create and configure a Forest agent.
Parameters: Example:
Only enable useUnsafeActionEndpoint if you specifically need index-free Smart Action routes.
It removes the positional index (/_actions/{collection}/{slug} instead of /_actions/{collection}/{index}/{slug}), which can make two action names collide on the same route.
When enabled, the agent refuses to start if two actions on the same collection resolve to the same slug.

agent.addDataSource(factory, options?)

Add a datasource to the agent.
Parameters: Example:

agent.customizeCollection(name, callback)

Customize a specific collection with the provided callback.
Example:

agent.addChart(name, definition)

Create a datasource-level API chart.
Example:

agent.removeCollection(…names)

Remove collections from the exported schema (they remain usable within the agent).
Example:

agent.use(plugin, options?)

Load a plugin across all collections.
Example:

agent.start()

Start the agent and connect to Forest servers.
Example:

agent.stop()

Stop the agent and close all connections.

agent.restart()

Reconstruct routing and remount routes at runtime. Called when customizations are refreshed externally (e.g. in cloud environments).

agent.addAi(provider)

Route Forest’s AI features (natural language search, actions, etc.) through your own agent so your data never leaves your infrastructure. Pass a provider built with createAiProvider (from @forestadmin/ai-proxy); openai and anthropic are supported. See Self-hosted AI for the full guide.
Can only be called once, calling it a second time throws an error. Example:

agent.mountAiMcpServer(options?)

Enable a Model Context Protocol (MCP) server on the agent, allowing AI assistants to interact with your data through standardized tools.
Parameters: Available tool names: 'describeCollection', 'list', 'listRelated', 'create', 'update', 'delete', 'associate', 'dissociate', 'getActionForm', 'executeAction' Example:
By default, the MCP server registers its endpoints at the host root:
When mounted inside an existing application, the MCP server intercepts the entire /oauth/* and /.well-known/* namespaces plus /mcp at the host root. Any request in those namespaces is captured by the MCP server — if it doesn’t serve that exact route (or your app already does), the request gets a 404/405 instead of reaching your app. For example, your own /oauth/callback or /.well-known/apple-app-site-association would break, not just OAuth. Set basePath to narrow the MCP server to a dedicated prefix (and just two suffixed .well-known paths) so your routes are left untouched.
Scoping under a prefix:
With basePath: '/ai', the OAuth and protocol routes move under the prefix. The .well-known discovery documents stay at the host root (as required by OAuth discovery, RFC 8414/9728) but are served at prefix-suffixed paths, so they no longer collide with your application’s own root .well-known routes: MCP clients discover these endpoints automatically from the metadata, so no client-side configuration is needed.
The prefix applies to all routes, including the protocol endpoint — so basePath: '/mcp' yields /mcp/mcp. Use a distinct prefix such as /ai to avoid the repetition.
Because the .well-known discovery documents must stay at the origin root, basePath requires the agent to be served at the domain root. If your agent’s URL already includes a path (e.g. https://host/api), setting basePath throws at startup. And root /.well-known/* requests must still reach the agent — a reverse proxy that forwards only /<prefix>/* will break discovery.
You can also configure enabled tools via the FOREST_MCP_ENABLED_TOOLS environment variable (comma-separated tool names), or set the server port with MCP_SERVER_PORT (default: 3931).

agent.updateTypesOnFileSystem(typingsPath, typingsMaxDepth)

Update the TypeScript typings file generated from your datasources.
Example:

agent.generateSchemaOnly()

Build the schema (.forestadmin-schema.json) and the TypeScript typings and write them to disk without starting the agent or sending the schema to Forest. Useful for generating the schema at build time in a CI/CD pipeline, see Generate the schema at build time. Available since @forestadmin/agent 1.83.0.
It takes no arguments: it reads schemaPath, typingsPath and typingsMaxDepth from the options you passed to createAgent. It always writes the schema to schemaPath, and also writes the TypeScript typings to typingsPath in the same pass whenever that option is set. Unlike agent.start(), it always rebuilds the schema, even when isProduction is true, and it never contacts Forest, with one exception: if you enable experimental no-code customizations, it still fetches their configuration from the Forest API, so connectivity is required in that case.
Despite the name, Only means it only generates the files without starting the agent or sending the schema to Forest, not “the schema only”. If you want to regenerate only the typings, use agent.updateTypesOnFileSystem() instead.
Example:
This does not close your data source connections. In a one-shot script, close your data source (the SQL/Sequelize/Mongo client you passed in) or call process.exit() once it resolves, otherwise an open connection pool can keep the process alive.

Collection Customizer

Methods available when customizing a collection through agent.customizeCollection().

Actions

collection.addAction(name, definition)

Add an action to the collection.
Definition Properties: Execute Function:
ActionContext Properties:
  • context.collection - Collection instance
  • context.filter - Filter for selected records
  • context.caller - User who triggered the action
  • context.formValues - Form values submitted
ActionContext Methods:
  • context.getRecords(fields) - Get multiple records (Bulk/Single scope)
  • context.getRecordIds() - Get IDs of selected records
  • context.getCompositeRecordIds() - Get composite IDs of selected records
  • context.hasFieldChanged(fieldName) - Check if form field changed
  • context.getRecord(fields) - Get single record (Single scope only)
  • context.getRecordId() - Get single record ID (Single scope only)
  • context.getCompositeRecordId() - Get composite ID (Single scope only)
  • context.getField(fieldName) - Get single field value (Single scope only)
ResultBuilder Methods:
  • resultBuilder.success(message?, options?) - Success response
    • options.html - Custom HTML to display
    • options.invalidated - Array of collection names to refresh
  • resultBuilder.error(message?, options?) - Error response
    • options.html - Custom HTML to display
  • resultBuilder.webhook(url, method, headers, body) - Trigger webhook
  • resultBuilder.file(stream, filename, mimeType) - Return file download
  • resultBuilder.redirectTo(path) - Redirect to URL
  • resultBuilder.setHeader(name, value) - Add HTTP header to response
Example - Simple Action:
Example - Action with Form:
Example - File Generation:

Fields

collection.addField(name, definition)

Add a computed field to the collection.
Definition Properties: Column Types:
  • 'String' - Text
  • 'Number' - Numeric value
  • 'Boolean' - True/false
  • 'Date' - Date with time
  • 'Dateonly' - Date without time
  • 'Time' - Time only
  • 'Enum' - Enumeration
  • 'Json' - JSON object
  • 'Uuid' - UUID
  • 'Point' - Geographic point
  • 'File' - File reference
Example - Simple Computed Field:
Example - Async Computed Field:

collection.importField(name, options)

Import a field from a related collection.
Example:

collection.renameField(currentName, newName)

Rename a field in the exported schema.
Example:

collection.removeField(…names)

Remove fields from the exported schema (they remain usable within the agent).
Example:

collection.addFieldValidation(name, operator, value?)

Add a validation rule to a field.
Operators: 'Present', 'LongerThan', 'ShorterThan', 'Contains', 'Like', 'Match', 'GreaterThan', 'LessThan', 'Before', 'After' Example:

collection.setFieldNullable(name)

Mark a field as optional (nullable).
Your database might still refuse empty values if it requires one.
Example:

collection.replaceFieldWriting(name, definition)

Replace the write behavior of a field.
Example:

collection.replaceFieldBinaryMode(name, mode)

Choose how binary data should be transported to the GUI.
Modes:
  • 'datauri' - Best for file uploads, uses FilePicker widget
  • 'hex' - Best for short binary data like UUIDs
Example:

Relationships

collection.addManyToOneRelation(name, foreignCollection, options)

Add a many-to-one relationship.
Example:

collection.addOneToManyRelation(name, foreignCollection, options)

Add a one-to-many relationship.
Example:

collection.addOneToOneRelation(name, foreignCollection, options)

Add a one-to-one relationship.
Example:

collection.addManyToManyRelation(name, foreignCollection, throughCollection, options)

Add a many-to-many relationship.
Example:

collection.addExternalRelation(name, definition)

Add a virtual collection into the related data of a record.
Example:

Segments

collection.addSegment(name, definition)

Add a segment (saved filter) to the collection.
Example - Static Segment:
Example - Dynamic Segment:

Hooks

collection.addHook(position, type, handler)

Add a hook to execute code before or after operations.
Hook Types: 'List', 'Create', 'Update', 'Delete', 'Aggregate' Example - Before Hook:
Example - After Hook:

collection.replaceSearch(definition)

Replace the default search behavior.
Example:

collection.disableSearch()

Disable search functionality on the collection.

Sorting

collection.emulateFieldSorting(name)

Enable in-memory sorting on a field.
Example:

collection.replaceFieldSorting(name, equivalentSort)

Replace sorting implementation for a field.
Example:

collection.disableFieldSorting(name)

Disable sorting on a specific field.

Filtering

collection.emulateFieldFiltering(name)

Enable in-memory filtering on all operators for a field.

collection.emulateFieldOperator(name, operator)

Enable in-memory filtering for a specific operator on a field.
Example:

collection.replaceFieldOperator(name, operator, replacer)

Replace the implementation of a filter operator.
Example:

Charts

collection.addChart(name, definition)

Add a chart to the collection.
Example - Value Chart:
Example - Distribution Chart:
Example - Time-based Chart:

Collection Overrides

collection.overrideCreate(handler)

Replace the default create operation.
Example:

collection.overrideUpdate(handler)

Replace the default update operation.
Example:

collection.overrideDelete(handler)

Replace the default delete operation.
Example:

Other Methods

collection.disableCount()

Disable count in list view pagination for improved performance.

collection.use(plugin, options?)

Load a plugin on a specific collection.
Example:

Chart Result Builders

When creating charts with collection.addChart() or agent.addChart(), the result builder provides methods to format chart data.

resultBuilder.value(value, previousValue?)

Create a Value chart (single number).

resultBuilder.distribution(obj)

Create a Distribution/Pie chart.

resultBuilder.timeBased(timeRange, values)

Create a Time-based/Line chart.
Time Ranges: 'Day', 'Week', 'Month', 'Quarter', 'Year'

resultBuilder.multipleTimeBased(timeRange, dates, lines)

Create a Multi-line Time-based chart.

resultBuilder.percentage(value)

Create a Percentage chart.

resultBuilder.objective(value, objective)

Create an Objective chart (progress toward goal).

resultBuilder.leaderboard(obj)

Create a Leaderboard chart (sorted distribution).

resultBuilder.smart(data)

Create a Smart chart (custom format).

Form Field Types

Action forms support various field types with different widgets.

Basic Field Types

Available Types:
  • 'String' - Text input
  • 'Number' - Numeric input
  • 'Boolean' - Checkbox
  • 'Date' - Date picker
  • 'Dateonly' - Date without time
  • 'Time' - Time picker
  • 'Enum' - Single selection
  • 'EnumList' - Multiple selection
  • 'File' - File upload
  • 'FileList' - Multiple file upload
  • 'Json' - JSON editor
  • 'Collection' - Record picker
  • 'NumberList' - Array of numbers
  • 'StringList' - Array of strings

Enum Fields


Collection Fields

Pick a record from another collection:


Dynamic Dropdown


Conditional Fields

Show/hide fields based on other field values:

Dynamic Field Values


Read-Only Fields


ConditionTree Utilities

Build complex filter conditions programmatically.

ConditionTreeLeaf

Simple condition on a single field:

ConditionTreeBranch

Combine multiple conditions with AND/OR:

ConditionTree Factory


Available Operators

Comparison:
  • 'Equal', 'NotEqual'
  • 'GreaterThan', 'LessThan'
  • 'In', 'NotIn'
  • 'Present', 'Blank'
String:
  • 'Contains', 'NotContains'
  • 'StartsWith', 'EndsWith'
  • 'Like', 'ILike' (case-insensitive)
Date:
  • 'Before', 'After'
  • 'Today', 'Yesterday', 'PreviousWeek', 'PreviousMonth', 'PreviousQuarter', 'PreviousYear'
  • 'Past', 'Future'
Array:
  • 'IncludesAll', 'IncludesNone'

Caller

User information available in all contexts:

Filter


Projection

Specify which fields to retrieve:

Plugin: Flattener

@forestadmin/plugin-flattener flattens nested data structures (composite columns, relations, JSON columns) into individual top-level fields.

flattenColumn(dataSource, collection, options)

Decompose a column with a composite type into individual fields.
Options:

flattenRelation(dataSource, collection, options)

Import fields from a relation directly into the collection.
Options:

flattenJsonColumn(dataSource, collection, options)

Expand a JSON column into individual typed fields.
Options:

Package: Forest Cloud

@forestadmin/forest-cloud is a dev-only package that provides CLI tooling for cloud-hosted customization projects.

Installation

CLI Commands

bootstrap

Initialize a cloud customization project. Authenticates with Forest, creates a cloud-customizer directory, configures credentials, and generates type definitions.

update-typings

Regenerate TypeScript type definitions based on your current database structure and customization code.

login

Refresh your Forest authentication token.

Exported Types


Package: Agent Testing

@forestadmin/agent-testing provides utilities to test agent customizations locally without connecting to Forest servers.

createForestServerSandbox(port)

Start a local sandbox that mimics Forest servers.

createAgentTestClient(options)

Connect a test client to a running agent to simulate frontend requests.
Parameters:

Typical test workflow