Skip to content

Custom Functions

These offer a fast way to bring your existing functions to a Toolpad Studio page.

The most powerful way of bringing data into Toolpad Studio is through your own code. You can define functions inside toolpad/resources and use them when creating a query of this type. The following video shows how you can use this feature to read data from PostgreSQL.

Function editor

  • Function

    This corresponds to a function that you create on your file system, inside the toolpad/resources folder. For example, the default function in toolpad/resources/functions.ts looks like:

    export default async function handler(message: string) {
      return `Hello ${message}`;
  • Toolpad Studio custom functions run fully server-side in Node. For example, if you change the content of the above example to:
    export async function example() {
      return process.versions;

    You get the following response:

Server-side values

Using server-side values in custom functions

  • You can import and use any Node module in your custom functions.


To be really useful, you need to connect these queries with data present on your page. You can do so by creating parameters.

All function arguments will be available in the query editor to bind state to. Make sure to annotate them correctly with their TypeScript types. Toolpad Studio uses this information to present you with correctly typed databinding controls. For example:

export async function getAnimals(
  species: 'cat' | 'dog' | 'rabbit',
  name: string,
  minAge: number,
) {
  return db.queryAnimals({
    age: { min: minAge },
Controls for custom function parameters

Controls for custom function parameters

Secrets handling

Toolpad Studio has access to the environment variables defined in the .env file at the root of the project.

You can even directly use the environment variables when defining custom functions, as you normally would when writing backend code. For example:


And you can then use them in a custom function like so:

import { Configuration, OpenAIApi } from 'openai';

export async function askGPT(messages: string[]) {
  const configuration = new Configuration({
    apiKey: process.env.OPENAI_API_KEY,

  const openai = new OpenAIApi(configuration);
  const completion = await openai.createChatCompletion({
    model: 'gpt-3.5-turbo',
    messages: messages,

  const response =[0].message ?? {
    role: 'assistant',
    content: 'No response',

  return response;

You can then use this function on your page:

Custom function with secret

Using a custom function with environment variables

Request context

When you run Toolpad Studio in an authenticated context it may be useful to be able to access authentication information in backend functions. For this purpose we offer the getContext API which allows you to inspect the cookies of the request that initiated the backend function.

Access cookies with context.cookies

import { getContext } from '@toolpad/studio/server';
import { parseAuth } from '../../src/lib/auth';

export async function myBackendFunction() {
  const ctx = getContext();
  const user = await parseAuth(ctx.cookie.authentication);
  return user?.id;

Write cookies with context.setCookie

You can also use the context to set a cookie, which can subsequently be used in other backend functions called from your Toolpad Studio application. Example:

import { getContext } from '@toolpad/studio/server';
import * as api from './myApi';


export async function login(user: string, password: string) {
  const token = await api.login(user, password);
  const { setCookie } = getContext();
  setCookie(MY_COOKIE_NAME, token);

export async function getData() {
  const { cookies } = getContext();
  const token = cookies[MY_COOKIE_NAME];
  return api.getData(token);

Get the current authenticated session with context.session

If your Toolpad Studio app has authentication enabled, you can get data from the authenticated session, such as the logged-in user's email, name or avatar. Example:

import { getContext } from '@toolpad/studio/server';

export async function getCurrentUserEmail() {
  const { session } = getContext();
  return session?;