# How to Extend Rocket.Chat Functionality Using the Apps-Engine Framework

> Learn how developers extend Rocket.Chat functionality with the Apps-Engine framework. Create sandboxed apps to add UI buttons, slash commands, and more without touching core code.

- Repository: [Rocket.Chat/Rocket.Chat](https://github.com/RocketChat/Rocket.Chat)
- Tags: how-to-guide
- Published: 2026-06-18

---

**Developers extend Rocket.Chat functionality by creating sandboxed Apps that interact with the core server through the Apps-Engine framework, utilizing controlled accessors to modify messages, register slash commands, add UI buttons, and expose HTTP endpoints without modifying core code.**

Rocket.Chat is an open-source communication platform designed for extensibility through its proprietary **Apps-Engine** architecture. Rather than modifying core server files, developers package custom behaviors as standalone **Rocket.Chat Apps** that run in isolated sandboxes. This approach ensures upgrade compatibility while providing deep integration capabilities through well-defined APIs.

## Understanding the Apps-Engine Architecture

The extension system centers on the `@rocket.chat/apps-engine` package, which implements a strict plugin architecture. When the server initializes, it instantiates a singleton **AppManager** ([`packages/apps/src/server/AppManager.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps/src/server/AppManager.ts)) that orchestrates the entire app lifecycle.

The AppManager performs four critical operations:

1. **Loads** installed app packages from the storage layer
2. **Compiles** each app into a sandboxed runtime via `AppRuntimeManager` (Node VM)
3. **Registers** listeners, commands, and endpoints through specialized managers (`AppListenerManager`, `AppSlashCommandManager`, `AppApiManager`, `UIActionButtonManager`)
4. **Handles** lifecycle events (`onInstall`, `onEnable`, `onDisable`, `onUninstall`, `onUpdate`) by delegating to the user-defined class extending the abstract `App` base class ([`packages/apps-engine/src/definition/App.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps-engine/src/definition/App.ts))

## Core Extension Points for Rocket.Chat Apps

### Event-Driven Listeners

Apps register for system events to intercept or react to platform activities. Available events include `IPreMessageSentPrevent`, `IPostMessageSent`, and `IPreRoomCreate`. When the core emits these events, the `AppListenerManager` invokes the corresponding handler within the app's sandbox.

### Slash Commands

Custom commands are registered through `configuration.slashCommands.provideSlashCommand()`, allowing apps to expose functionality via the message input box.

### UI Action Buttons

Developers inject interactive elements into the client interface using `configuration.uiActionButtons.provideButton()`, handled server-side by `UIActionButtonManager` ([`packages/apps/src/server/managers/UIActionButtonManager.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps/src/server/managers/UIActionButtonManager.ts)).

### Custom HTTP Endpoints

Apps expose REST APIs through `configuration.api.provideApi()`, managed by `AppApiManager` ([`packages/apps/src/server/managers/AppApiManager.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps/src/server/managers/AppApiManager.ts)), with configurable visibility (public or private).

### Data Persistence

The **IPersistence** accessor allows apps to store private data using `persistence.create()` and `persistence.update()`, ensuring isolated storage per app.

## Building a Minimal Rocket.Chat App

Every app extends the abstract `App` class and implements the `initialize` method to register capabilities. Here is a complete "Hello World" example that demonstrates slash commands and message listeners:

```typescript
// src/App.ts
import {
  IAppAccessors,
  IConfigurationExtend,
  IEnvironmentRead,
} from '@rocket.chat/apps-engine/definition/accessors';
import { App } from '@rocket.chat/apps-engine/definition/App';
import { IAppInfo } from '@rocket.chat/apps-engine/definition/metadata';

export class HelloWorldApp extends App {
  constructor(info: IAppInfo, logger: any, accessors?: IAppAccessors) {
    super(info, logger, accessors);
  }

  public async initialize(configuration: IConfigurationExtend, environment: IEnvironmentRead) {
    await this.registerCommand(configuration);
    await this.registerListener(configuration);
  }

  private async registerCommand(configuration: IConfigurationExtend) {
    await configuration.slashCommands.provideSlashCommand({
      command: 'hello',
      i18nDescription: 'Say hello',
      providesPreview: false,
      executor: async (context, read, modify, http, pers) => {
        const { user } = context;
        const message = modify.getCreator().startMessage()
          .setSender(user)
          .setRoom(context.getRoom())
          .setText(`👋 Hello, ${user.username}!`);
        await modify.getCreator().finish(message);
      },
    });
  }

  private async registerListener(configuration: IConfigurationExtend) {
    await configuration.messageListeners.provideMessageListener({
      eventName: 'IPostMessageSent',
      execute: async (context, read, modify) => {
        const { message } = context;
        if (/thanks/i.test(message.text || '')) {
          await modify.getCreator().addReaction(message.id, '👍');
        }
      },
    });
  }
}

```

This implementation leverages the **IModify** accessor to create messages and reactions, while the **IRead** accessor (available in parameters) provides read-only access to rooms and users.

## Advanced Extension Patterns

### Adding UI Action Buttons

To extend Rocket.Chat functionality with client-side interactions, apps register UI buttons that appear in message contexts:

```typescript
await configuration.uiActionButtons.provideButton({
  appId: this.getID(),
  id: 'open-ticket',
  label: { en: 'Open Ticket' },
  context: ['message'],
  action: async (context, read, modification, http, pers) => {
    const { message } = context;
    const ticketRoom = await modification.getCreator().startRoom()
      .setType('c')
      .setDisplayName(`Ticket for ${message.sender.username}`)
      .setCreator(message.sender)
      .finish();

    await modification.getNotifier().notifyUser(message.sender, {
      rid: ticketRoom.id,
      msg: 'Your ticket has been created!',
    });
  },
});

```

The `UIActionButtonManager` processes these registrations and coordinates with the client-side orchestrator ([`apps/meteor/client/apps/orchestrator.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/apps/meteor/client/apps/orchestrator.ts)) to render the components.

### Exposing Custom HTTP Endpoints

Apps can create private or public REST endpoints to integrate external services:

```typescript
await configuration.api.provideApi({
  path: '/external-data',
  visibility: ApiVisibility.PRIVATE,
  endpoints: [
    {
      path: '/fetch',
      method: HttpMethod.GET,
      auth: {
        requiredPermissions: [],
      },
      endpoint: async (request, read, modify, http, pers) => {
        const external = await http.get('https://api.example.com/data');
        return {
          status: HttpStatusCode.OK,
          headers: { 'Content-Type': 'application/json' },
          content: JSON.stringify(external.data),
        };
      },
    },
  ],
});

```

The `AppApiManager` routes incoming requests to the appropriate sandboxed endpoint, enforcing the specified authentication and permissions.

## Key Source Files in the Apps-Engine

Understanding the following source files is essential for developers looking to extend Rocket.Chat functionality:

- **[`packages/apps/src/server/AppManager.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps/src/server/AppManager.ts)**: The core singleton responsible for loading, compiling, and managing the lifecycle of all installed apps.
- **[`packages/apps-engine/src/definition/App.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps-engine/src/definition/App.ts)**: The abstract base class that every developer-written app must extend.
- **[`packages/apps/src/server/managers/AppListenerManager.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps/src/server/managers/AppListenerManager.ts)**: Registers and unregisters event listeners for app callbacks.
- **[`packages/apps/src/server/managers/AppSlashCommandManager.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps/src/server/managers/AppSlashCommandManager.ts)**: Handles registration and execution of custom slash commands.
- **[`packages/apps/src/server/managers/AppApiManager.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps/src/server/managers/AppApiManager.ts)**: Manages custom HTTP endpoints exposed by apps.
- **[`packages/apps/src/server/managers/UIActionButtonManager.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps/src/server/managers/UIActionButtonManager.ts)**: Processes UI action button registrations for client rendering.
- **[`packages/apps/src/server/runtime/AppRuntimeManager.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps/src/server/runtime/AppRuntimeManager.ts)**: Creates and manages sandboxed Node VM runtimes for app isolation.
- **[`apps/meteor/client/apps/orchestrator.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/apps/meteor/client/apps/orchestrator.ts)**: Client-side bridge that loads UI-kit definitions from server-side apps.

## Summary

- **Rocket.Chat Apps** provide the official mechanism to extend Rocket.Chat functionality without modifying core server code.
- The **Apps-Engine** architecture uses a sandboxed runtime (Node VM) to ensure security and stability.
- Developers interact with the platform through **accessors** (`IRead`, `IModify`, `IHttp`, `IPersistence`) injected into lifecycle methods.
- Extension points include **event listeners**, **slash commands**, **UI action buttons**, and **custom HTTP endpoints**.
- The **AppManager** singleton orchestrates app lifecycles while specialized managers handle specific capability registrations.

## Frequently Asked Questions

### What programming language is used to extend Rocket.Chat functionality?

Rocket.Chat Apps are written in **TypeScript** (compiled to JavaScript). The Apps-Engine provides type definitions in the `@rocket.chat/apps-engine` package, ensuring type-safe access to platform APIs and accessors.

### How do Rocket.Chat Apps differ from traditional server modifications?

Unlike direct server modifications that alter core files and break during upgrades, Apps run in **isolated sandboxes** managed by `AppRuntimeManager`. They interact with the host exclusively through well-defined accessors, ensuring the core server remains stable and upgrade-compatible.

### Can Apps interact with external APIs and services?

Yes. The **IHttp** accessor allows apps to make outbound requests to external services. Additionally, apps can expose their own endpoints via `provideApi()`, managed by `AppApiManager`, to receive inbound webhooks or serve data to external systems.

### Where are Apps stored and how are they lifecycle-managed?

Apps are stored in the server's database and loaded at startup by **AppManager** ([`packages/apps/src/server/AppManager.ts`](https://github.com/RocketChat/Rocket.Chat/blob/main/packages/apps/src/server/AppManager.ts)). The manager handles installation, enabling, disabling, updating, and uninstallation by calling the corresponding lifecycle methods (`onInstall`, `onEnable`, `onDisable`, `onUninstall`, `onUpdate`) defined in the app's main class.