> For the complete documentation index, see [llms.txt](https://manual.bubble.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://manual.bubble.io/account-and-marketplace/building-plugins/building-actions.md).

# Building actions

<details>

<summary>System hard limits</summary>

When creating plugins for Bubble, it's important to be mindful of Bubble's hard system limits. These constraints for plugin development mirror those in general Bubble development. The article below covers this subject:

Article: [Hard limits](/help-guides/maintaining-an-application/performance-and-scaling/hard-limits.md)

</details>

Building actions is quite similar to building elements. You add them to your plugin and test them the same way, using a test app. Web actions are written in JavaScript, and mobile actions in React Native.

## Action types

There are two types of actions you can build: client-side and server-side.

<table><thead><tr><th width="151.05078125">Type</th><th>What it's for</th></tr></thead><tbody><tr><td>Client-side</td><td>Page interactions, sending data to analytics, converting a credit card into a token using a library, and similar tasks that run in the user's browser or app.</td></tr><tr><td>Server-side</td><td>Making custom calls to external services, running a matching algorithm, or performing an advanced computation. Server-side actions can return data that later actions in the workflow can use.</td></tr></tbody></table>

## Defining an action

As with elements, you define the action's fields, then use those values in your code through the `properties` object. See the [previous article](/account-and-marketplace/building-plugins/building-elements.md) for the field options available when adding fields to an element or action.

The core of the action is the function that runs when a workflow reaches it. This function is called with the `properties` and `context` objects. You can see contextual documentation for both in the editor. If your action references an imported React Native library, you access it through `context` as well.

As with element functions, keep in mind that your code may run more than once to fetch data. It's best to load data at the start of your functions, before modifying any state outside the function. See the [next article](/account-and-marketplace/building-plugins/loading-data.md) for more.

Here's an example of an action that sends data to Facebook Pixel:

<figure><img src="https://34394582-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M5sbzwG7CljeZdkntrL%2Fuploads%2F6XRmWhIJbk8WoTq2l8yP%2Fcode.png?alt=media&amp;token=e8eb0f49-d81b-4d7c-9fbd-d59ff8068ac1" alt=""><figcaption></figcaption></figure>

## Using node modules in a server-side action

You can extend a server-side action's functionality with node modules. Select **This action uses node modules**, then paste your package.json into the box that appears. You can also list modules by hand; only the `dependencies` section is used. Require your modules inside your function as you normally would.

<figure><img src="https://34394582-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M5sbzwG7CljeZdkntrL%2Fuploads%2F5kd2RccOoEqwKXK2PxtK%2Faction-code.png?alt=media&amp;token=f647d11f-1f85-4ccd-9f41-0b3878002f28" alt=""><figcaption></figcaption></figure>

When you add or update your list of modules, Bubble builds a deployment package to run your action. This can take a few minutes, and you start it by clicking the link that appears below the box.

## Notes and limitations

### File sizes

**File inputs.** Server-side plugin actions encode files using base64, which increases file size by roughly 1.25x. Try to avoid passing files larger than 5MB through server-side plugin actions. File URLs are a good alternative to file inputs.

**API call response size.** There's a hard limit of 50MB for responses to an outgoing API call made with a plugin (this includes the API Connector). Exceeding it generates an error in the logs: "response too large."

### Option sets

Option sets can't be retrieved through server-side actions. Client-side, an option set is represented as a `{ listProperties, get }` object, where `listProperties` lists all the fields on the option, and `get('field')` gets the value of that field on the option set.
