> ## Documentation Index
> Fetch the complete documentation index at: https://developers.hubspot.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

---
id: 815f5fdc-5284-45c2-877c-9836dc0b9a80
---

# Serverless functions reference (projects)

> Reference information for serverless functions built with developer projects, including serverless.json, function files, endpoints, CLI commands, and managing packages.

export const SupportedProducts = ({marketing, sales, service, cms, data, commerce, marketingLevel, salesLevel, serviceLevel, cmsLevel, dataLevel, commerceLevel}) => {
  const translations = {
    description: "Requires one of the following products or higher.",
    productNames: {
      marketing: "Marketing Hub",
      sales: "Sales Hub",
      service: "Service Hub",
      cms: "Content Hub",
      data: "Data Hub",
      commerce: "Commerce Hub"
    },
    tiers: {
      free: "Free",
      starter: "Starter",
      professional: "Professional",
      enterprise: "Enterprise"
    }
  };
  const translateTier = tier => {
    if (!tier) return '';
    const lowerTier = tier.toLowerCase();
    return translations.tiers[lowerTier] || tier;
  };
  const products = [{
    name: marketing ? translations.productNames.marketing : '',
    level: translateTier(marketingLevel),
    icon: "https://mintlify-assets.b-cdn.net/Icons/marketing-bolt.svg",
    alt: "Marketing Hub"
  }, {
    name: sales ? translations.productNames.sales : '',
    level: translateTier(salesLevel),
    icon: "https://mintlify-assets.b-cdn.net/Icons/sales-star.svg",
    alt: "Sales Hub"
  }, {
    name: service ? translations.productNames.service : '',
    level: translateTier(serviceLevel),
    icon: "https://mintlify-assets.b-cdn.net/Icons/service-heart.svg",
    alt: "Service Hub"
  }, {
    name: cms ? translations.productNames.cms : '',
    level: translateTier(cmsLevel),
    icon: "https://mintlify-assets.b-cdn.net/Icons/content-play.svg",
    alt: "Content Hub"
  }, {
    name: data ? translations.productNames.data : '',
    level: translateTier(dataLevel),
    icon: "https://developers.hubspot.com/hubfs/Knowledge_Base_2023-24-25/subscription_key_icons/operations_icon.svg",
    alt: "Data Hub"
  }, {
    name: commerce ? translations.productNames.commerce : '',
    level: translateTier(commerceLevel),
    icon: "https://developers.hubspot.com/hubfs/Knowledge_Base/subscription_key_icons/commerce_icon.svg",
    alt: "Commerce Hub"
  }].filter(product => product.name && product.level);
  if (products.length === 0) return null;
  return <div>
      <div className="text-sm mb-2">{translations.description}</div>
      <div className={`grid ${products.length === 1 ? 'grid-cols-1' : 'grid-cols-2'} gap-1.5`}>
        {products.map((product, index) => <div key={index} style={{
    display: 'flex',
    alignItems: 'center'
  }}>
            <img src={product.icon} alt={product.alt} className="w-3.5 h-3.5 mr-1.5 mt-2.5 mb-2.5 flex-shrink-0 align-middle" />
            <span className="font-medium mr-1 text-sm">{product.name} -</span>
            <span className="text-sm">{product.level}</span>
          </div>)}
      </div>
    </div>;
};

<Accordion title="Supported products" defaultOpen="true" icon="cubes">
  <SupportedProducts cms={true} cmsLevel="enterprise" />
</Accordion>

<Warning>
  **Please note:**

  This page contains reference documentation for serverless functions in CMS projects built on [version 2025.1](/developer-tooling/platform/versioning) of the developer platform. For serverless functions built using the design manager, check out the [serverless functions (design manager) reference](/cms/reference/serverless-functions/serverless-functions). If you're looking to implement serverless functions in a legacy app UI extension, check out the [legacy app serverless functions guide](/apps/legacy-apps/private-apps/build-with-projects/serverless-functions).
</Warning>

On this page, you'll find reference information for implementing serverless functions in CMS projects built on [version 2025.1](/developer-tooling/platform/versioning) of the developer platform. Though conceptually the same as serverless functions built with the design manager, project-based serverless functions require a different `serverless.json` configuration, enable the use of third-party dependencies, and have more direct access to private app access tokens for authentication.

For a high-level overview of serverless functions, see the [serverless functions overview](/cms/start-building/features/serverless-functions/overview). And to get started building project-based serverless functions, check out the [get started guide](/cms/start-building/features/serverless-functions/getting-started-with-serverless-functions).

## File structure

Serverless functions are packaged within a `.functions` directory within the `app` directory of a project. The `.functions` directory can have any name you'd like, as long as it ends in `.functions`.

In the `.functions` directory, you'll need to include three files:

* `serverless.json`: the configuration file for the serverless function.
* `function.js`: A JavaScript file containing the code to execute. This file can have any name, and you'll reference the file name in `serverless.json`.
* A `package.json` configuration file to contain the dependencies needed to execute the function.

```shell theme={null}
project-folder/
│── src/
├──── app
│     ├── app.json
│     ├── app.functions/
│       ├── function.js
│       ├── package.json
│       └── serverless.json
└─ hsproject.json
```

Below, learn more about each file.

## Serverless.json

The `serverless.json` file stores the serverless function configuration. This is a required file, and maps your functions to their endpoints.

<Warning>
  **Please note:**

  If you're upgrading your existing serverless functions to be built using developer projects, note that the `runtime`, `environment,` and `version` fields have been removed.
</Warning>

```js theme={null}
{
  "appFunctions": {
     "functionName": {
      "file": "function.js",
      "secrets": [],
      "endpoint": {
        "path": "fetch-quote",
        "method": ["GET"]
       }
    }
  }
}

```

| Field          | Type   | Description                                                                                                                                                                                                                                                                   |
| -------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `functionName` | Object | An object containing the serverless function's configuration details. This object can have any name.                                                                                                                                                                          |
| `file`         | String | The name of the JavaScript file containing the serverless function code to execute.                                                                                                                                                                                           |
| `secrets`      | Array  | An array containing names of secrets that the function will use for authenticating requests. Learn more about [authentication](#authentication).                                                                                                                              |
| `endpoint`     | Object | An object containing details about the endpoint that you can hit to invoke the function. The `path` field defines the last value in the `/hs/serverless/<path>` endpoint path, while the `method` field defines the request method. Learn more about [endpoints](#endpoints). |

<Warning>
  **Please note:**

  Do not assign the same name to your secrets and environment variables. Doing so will result in conflicts when returning their values in the function.
</Warning>

### Function file

Serverless functions built with developer projects use the [NodeJS](https://nodejs.org/en/about/) runtime (version 18 and higher). Lower versions of Node cannot be specified. In addition, serverless functions should be asynchronous, using `await` and `try`/`catch` instead of promise chaining.

Below is an example of JavaScript code that can be executed by a serverless function. This code is taken from the [get started with serverless functions guide](/cms/start-building/features/serverless-functions/getting-started-with-serverless-functions) and fetches a quote via the [Zen Quotes API](https://zenquotes.io/). Learn more about [authenticating requests](#authentication).

```js theme={null}
const axios = require("axios");

exports.main = async context => {
  try {
    // Make GET request to the ZenQuotes API
    const response = await axios.get("https://zenquotes.io/api/random");

    // Extract the quote data (first item in the array)
    const quoteData = response.data[0];

    // Log the quote and author to console
    console.log(`"${quoteData.q}" — ${quoteData.a}`);

    // Return a properly formatted response with status code and body
    return {
      statusCode: 200,
      body: quoteData,
      headers: {
        "Content-Type": "application/json",
      },
    };
  } catch (error) {
    // Handle any errors that occur during the request
    console.error("Error fetching quote:", error.message);

    // Return an error response
    return {
      statusCode: 500,
      body: { error: "Failed to fetch quote" },
      headers: {
        "Content-Type": "application/json",
      },
    };
  }
};
```

### package.json

In the `package.json` file, you can specify dependencies to include in the `dependencies` field. When the app is built, dependencies will be bundled with your function code. All dependencies must be published to NPM and be public.

For example, if you wanted to add the lodash library in a serverless function, you would first update package.json to include the dependency:

```json theme={null}
{
  "name": "example-serverless-function",
  "version": "0.1.0",
  "author": "HubSpot",
  "license": "MIT",
  "dependencies": {
    "@hubspot/api-client": "^7.0.1",
    "axios": "^0.27.2",
    "lodash": "^4.17.21"
  }
}
```

## Endpoints

Serverless functions for the CMS are invoked by calling its public URL, which has the following structure:

`https://<domain>/hs/serverless/<path>`.

| Parameter         | Description                                                                                                                       |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `<domain>`        | A domain connected to the HubSpot account. This can be any connected domain, including the default `<hubId>.hs-sites.com` domain. |
| `/hs/serverless/` | The path reserved for serverless functions. All endpoints exist inside this path.                                                 |
| `<path>`          | The `path` value specified in the `serverless.json` file.                                                                         |

For example, if both website.com and subdomain.brand.com are connected to the account, you could call the function using `https://website.com/hs/serverless/<path>` or `https://subdomain.brand.com/hs/serverless/<path>`. If the serverless function's `path` field was set to `fetch-quote`, the full URL would be:

`https://website.com/hs/serverless/fetch-quote`

## Authentication

Serverless functions requests built with projects can be authenticated using either the app's private app access token or a secret. Calls authenticated with private app access tokens count against your API call limits.

* Private app access tokens can be used for authenticating HubSpot API requests, using the value `PRIVATE_APP_ACCESS_TOKEN`.
* Secrets can be referenced by name, and must also be included in the `secrets` array of the `serverless.json` file. To create, manage, and view secrets associated with your account, use the set of `hs secrets` [CLI commands](/developer-tooling/local-development/hubspot-cli/reference#add-a-secret).
* In the function file, authentication for app tokens and secrets are both accessed with `process.env`.

Below is an example of the same request but using the private app access token or a secret for authentication (found in the `headers` object).

<Tabs>
  <Tab title="Private app access token">
    ```js theme={null}
    const axios = require("axios");

    exports.main = async (context = {}) => {
      try {
        const response = await axios.get(
          `https://api.hubspot.com/cms/v3/hubdb/tables/109906251/rows?sort=random()&limit=1`,
          {
            headers: {
              Authorization: `Bearer ${process.env.PRIVATE_APP_ACCESS_TOKEN}`,
              "Content-Type": "application/json",
            },
          }
        );
        return response.data.results;
      } catch (error) {
        console.log("Error details:", error);
      }
    };
    ```
  </Tab>

  <Tab title="Secret auth">
    Note that, for secret authentication, if your secret name was `my_secret`, then the `serverless.json` file would need to include `"secrets": ["my_secret"]`.

    ```js theme={null}
    const axios = require("axios");

    exports.main = async (context = {}) => {
      try {
        const response = await axios.get(
          `https://api.hubspot.com/cms/v3/hubdb/tables/109906251/rows?sort=random()&limit=1`,
          {
            headers: {
              Authorization: `Bearer ${process.env.my_secret}`,
              "Content-Type": "application/json",
            },
          }
        );
        return response.data.results;
      } catch (error) {
        console.log("Error details:", error);
      }
    };
    ```
  </Tab>
</Tabs>

## Context object

The context object contains contextual information about the function's execution, stored in the following parameters.

| Parameter   | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `accountId` | The HubSpot account ID containing the function.                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `body`      | Populated if the request method is `POST` with a content type of `application/json`.                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `contact`   | If the request is from a cookied contact, the contact object will be populated with a set of basic contact properties along with the following information:<ul><li>`vid`: The contact’s visitor ID.</li><li>`isLoggedIn`: when using [CMS Memberships](https://knowledge.hubspot.com/website-pages/require-member-registration-to-access-private-content), this will be `true` if the contact is logged in to the domain.</li><li>`listMemberships`: an array of contact list IDs that this contact is a member of.</li></ul> |
| `headers`   | Contains the [headers](#headers) sent from the client hitting your endpoint.                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `params`    | Populated with query string values, along with any HTML Form-POSTed values. These are structured as a map with strings as keys and an array of strings for each value.                                                                                                                                                                                                                                                                                                                                                        |

### Headers

If you need to know the headers of the client that's hitting your endpoint, you can access them through `context.headers`, similar to how you would access information through `context.body`.

Below, review some of the common headers that HubSpot provides. For a full list, see [MDN's HTTP headers documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers).

| header                      | Description                                                                                                                                                                                                                                     |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `accept`                    | Communicates which content types the client understands, expressed as [MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types). [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept). |
| `accept-encoding`           | Communicates the content encoding the client understands. [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Encoding).                                                                                       |
| `accept-language`           | Communicates which human language and locale is preferred. [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Language).                                                                                      |
| `cache-control`             | Holds directives for caching. [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control).                                                                                                                     |
| `connection`                | Communicates whether the network connection stays open. [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Connection).                                                                                              |
| `cookie`                    | Contains cookies sent by the client. [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cookie).                                                                                                                     |
| `host`                      | Communicates the domain name and TCP port number of a listening server. [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Host).                                                                                    |
| `true-client-ip`            | IP address of the end-user. [See Cloudflare true-client-ip](https://developers.cloudflare.com/network/true-client-ip-header/).                                                                                                                  |
| `upgrade-insecure-requests` | Communicates the clients preference for an encrypted and authenticated response. [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Upgrade-Insecure-Requests).                                                      |
| `user-agent`                | Vendor-defined string identifying the application, operating system, application vendor, and version. [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/User-Agent).                                                |
| `x-forwarded-for`           | Identifies the originating IP address of a client through a proxy or load balancer. [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For).                                                             |

#### Redirect by sending a header

You can perform a redirect from your serverless function by sending a response with a *location* header and `301` statusCode.

```js theme={null}
sendResponse({
  statusCode: 301,
  headers: {
    Location: "https://www.example.com",
  },
});
```

## Limits

Serverless functions are intended to be fast and have a narrow focus. To enable quick calls and responses, HubSpot serverless functions have the following limits:

* 50 secrets per account.
* 128MB of memory.
* No more than 100 endpoints per HubSpot account.
* You must use `contentType` of `application/json` when calling a function.
* Serverless function logs are stored for 90 days.
* 6MB on an AWS Lambda invocation payload.

**Execution limits**

* Each function has a maximum of 10 seconds of execution time.
* Each account is limited to 600 total execution seconds per minute.

This means either of these scenarios can happen:

* 60 function executions that take 10 seconds each to complete.
* 6,000 function executions that take 100 milliseconds to complete.

Functions that exceed those limits will throw an error. Execution count and time limits will return a `429` response. The execution time of each function is included in the [serverless function logs](/developer-tooling/local-development/hubspot-cli/reference#get-logs).

To assist in avoiding these limits, limit data is provided automatically to the [function context](/cms/reference/serverless-functions/serverless-functions#function-file) during execution. You can use that to influence your application to stay within those limits. For example, if your application requires polling your endpoint, then you can return with your data a variable to influence the frequency of the polling. That way when traffic is high you can slow the rate of polling avoiding hitting limits, then ramp it back up when traffic is low.
