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

# Express

> `@runonatlas/express` is our Express.js library for Atlas, which provides all the middleware and backend resources you need.

## Installation

<Tabs>
  <Tab title="npm">
    ```bash Terminal theme={null}
    npm install @runonatlas/express
    ```
  </Tab>

  <Tab title="pnpm">
    ```bash Terminal theme={null}
    pnpm add @runonatlas/express
    ```
  </Tab>

  <Tab title="yarn">
    ```bash Terminal theme={null}
    yarn add @runonatlas/express
    ```
  </Tab>
</Tabs>

## Initialization

<Warning>
  This only covers the backend initialization with Express. You will also need
  to initialize your frontend. For example, [React](/developer-portal/sdk/react)
  or [Next.js](/developer-portal/sdk/next).
</Warning>

Initializing the Atlas SDK is very easy. You just need to follow these steps:

<Steps>
  <Step title="Set the Atlas API key in the environment variables">
    You can get it from the [Atlas Dashboard](https://app.runonatlas.com).

    ```bash .env theme={null}
    ATLAS_API_KEY="INSERT_YOUR_ATLAS_API_KEY"
    ```
  </Step>

  <Step title="Create the Atlas Express Client">
    To initialize the Atlas SDK, you need to instantiate the Atlas Client with the following parameters:

    1. Your Atlas API key.
    2. A function that returns the user id given a request object.

    <Tabs>
      <Tab title="Using Clerk">
        When using Clerk, you just need to pass the getAuth function to get the userId.

        <CodeGroup>
          ```typescript src/index.ts [expandable] {6-8,12} theme={null}
          import { AtlasExpressClient } from "@runonatlas/express";
          import { clerkMiddleware, getAuth } from "@clerk/express";
          import express from "express";

          const app = express();
          const atlas = new AtlasExpressClient(
            (req) => getAuth(req).userId
          );

          app.use(clerkMiddleware());

          app.use("/", atlas.router);
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Using any authentication provider">
        You just need to pass a function that returns the userId from the request.

        <CodeGroup>
          ```typescript src/index.ts [expandable] {6-11} theme={null}
          import { AtlasExpressClient } from "@runonatlas/express";
          import express from "express";
          import { getAuth } from "@clerk/express";

          const app = express();
          const atlas = new AtlasExpressClient(
            (req) => getAuth(req).userId
          );

          // ... Remaining code
          ```
        </CodeGroup>
      </Tab>
    </Tabs>
  </Step>
</Steps>

<AccordionGroup>
  <Accordion title="Having CORS issues?" icon="server">
    If you are having CORS issues only with Atlas, it probably means that your CORS middleware is running after the Atlas server. Make sure to place the CORS middleware before the Atlas server. For example:

    <CodeGroup>
      ```typescript src/index.ts [expandable] {11} theme={null}
      import { AtlasExpressClient } from "@runonatlas/express";
      import express from "express";
      import { clerkMiddleware, getAuth } from "@clerk/express";
      import cors from "cors";
      import corsOptions from "./corsOptions";

      const app = express();
      const atlas = new AtlasExpressClient((req) => getAuth(req).userId);
      app.use(cors(corsOptions));
      app.use(clerkMiddleware());

      app.use("/", atlas.router);
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>

## Restrict user access based on their subscriptions

You can prevent users from accessing restricted parts of your application based on their subscription. To do so, you can use our backend protection features.

### Backend Protection

In order to prevent users from using certain endpoints unless they have a plan with the required features, we only need to add a middleware.

```typescript {3} theme={null}
app.post(
  "/api/generate-caption",
  atlas.createFeaturesMiddleware(["data-explorer"]), // Add this line
  (req, res) => {
    // Your endpoint logic here
  }
);
```

This will automatically prevent users who don't have the data-explorer feature in their active plan from accessing the endpoint.

<Warning>
  Remember that you need to have followed the [installation
  guide](#installation) before you can use any of these features.
</Warning>

{" "}

## Limit-based features

Sometimes, just having a feature as enabled or disabled is not enough, and our pricing models require limits to be set. For example, 5 users per account, or 20GB of storage.
Setting this up with Atlas is very easy. And, if at some point the limits change, you won't need to change the code again!

### Configuring the backend

The backend needs to understand what the limits are and how to check if the limit has been reached. To do so, when initializing the Atlas Client, you can provide a `limits` object with callbacks per each limit that you might want to use.

For example, given a feature whose id is `data-explorer`, you can provide a callback to check if the limit has been reached:

```typescript src/index.ts [expandable] {10-16} theme={null}
import { AtlasExpressClient } from "@runonatlas/express";
import express from "express";
import { getAuth } from "@clerk/express";
import { prisma } from "./db";

const app = express();
const atlas = new AtlasExpressClient((req) => getAuth(req).userId, {
  limits: {
    "data-explorer": (userId: string) =>
      prisma.explorations.count({
        where: {
          userId,
        },
      }),
  },
});

// ... Remaining code
```

Now, every time you the application needs to check if the `data-explorer` feature is available, Atlas will use the callback to compute it.

<Accordion title="What happens if you don't configure a limit?" icon="server">
  By default, if you haven't configured a limit callback, Atlas will deny access to the feature if it has a limit. You can easily override this behavior. For example:

  ```typescript src/index.ts [expandable] {10-12} theme={null}
  import { AtlasExpressClient } from "@runonatlas/express";
  import express from "express";
  import { getAuth } from "@clerk/express";
  import { prisma } from "./db";

  const app = express();
  const atlas = new AtlasExpressClient((req) => getAuth(req).userId, {
    baseClientOptions: {
      allowUnknownLimits: true,
    },
  });
  ```
</Accordion>

## Usage-based and Credit-based features

Usage-based and credit-based features allow you to bill customers based on their consumption.
These features track usage events and apply billing according to your pricing model configuration.

### Understanding billing types

Atlas supports two types of billing for consumption-based features:

**Usage-based billing**: Events are rolled up for the entire billing period, the price is applied, and the user
is billed in arrears according to what they used. This is traditional usage-based billing where customers pay
for what they consume after the fact.

**Credit-based billing**: Users are allocated a specific amount of a custom pricing unit (e.g., credits) each month.
When an event is received in Atlas that matches a credit-based price, their balance of custom pricing units is
instantly deducted. This provides near real-time consumption tracking with immediate balance updates.

<Accordion title="Blocking consumption-based feature access and eventual consistency" icon="exclamation-triangle">
  Atlas offers the ability to block access to a usage-based and credit-based features
  via the **Max usage** and **Block overage** options, respectively.

  **Max usage**: (Number) The maximum amount of a usage-based feature a customer is allowed to consume within a single billing
  period. If specified, Atlas will block access after usage reaches the amount specified and then unblock access at the start
  of the next billing period. If not specified, Atlas will allow unlimited usage in any given billing period.

  **Block overage**: (Boolean) Whether or not to prevent a customer from drawing custom pricing unit balance negative.
  If enabled, Atlas will block access to a feature when a balance of 0 has been detected. Otherwise, Atlas will continue
  accepting events and further reduce the customers credit balance negative. The next allocation of custom pricing units
  will be applied as normal, increasing the customers balance from the current negative balance by the amount of the
  allocation.

  Because Atlas's event ingestion system is designed to be eventually
  consistent, it is possible for a small number of events to be processed before
  Atlas feature flagging has recognized that the customer has hit a balance of 0.
  This means that small overages are possible even if `blockOverage` is enabled.
  For more real time access control, please reach out to customer support at
  [support@runonatlas.com](mailto:support@runonatlas.com).
</Accordion>

### Options to report events

To bill your customers correctly, your application must send an event to Atlas each time a usage-based or credit-based feature is consumed. There are three ways to report these usage events:

#### Option A: Automatic Reporting (Recommended)

**Enjoy Atlas' magic!** By default, the Atlas Express Client automatically sends a single usage event to Atlas every time an endpoint protected by the `createFeaturesMiddleware` is called.

```typescript src/index.ts [expandable] {3} theme={null}
app.post(
  "/api/generate-caption",
  atlas.createFeaturesMiddleware(["usage-based-feature"]), // Same middleware as before. It's smart enough to know it now needs to send events
  (req, res) => {
    // Your endpoint logic here
  }
);
```

#### Option B: Report a Custom Quantity

If an endpoint's usage should count as more than one event, you can specify a fixed quantity directly in the middleware options.

```typescript src/index.ts [expandable] {3} theme={null}
app.post(
  "/api/generate-caption",
  atlas.createFeaturesMiddleware(["usage-based-feature"], {
    events: { quantity: 2 },
  }),
  (req, res) => {
    // Your endpoint logic here
  }
);
```

#### Option C: Manual Event Reporting

For more complex scenarios, such as when the event quantity depends on request-specific logic or needs to be sent conditionally, you can take full manual control. First, disable automatic sending for the middleware, then use the `atlas.client.enqueueEvents` method within your endpoint logic to report the usage.

```typescript src/index.ts [expandable] {3, 6-10} theme={null}
app.post(
  "/api/generate-caption",
  atlas.createFeaturesMiddleware(["usage-based-feature"], {
    events: { sendAutomatically: false },
  }),
  async (req, res) => {
    // Your endpoint logic here
    await atlas.client.enqueueEvents({
      customerId: getAuth(req).userId,
      featureIds: ["usage-based-feature"],
      quantity: Math.floor(Math.random() * 10),
    });
  }
);
```

<Accordion title="Can I disable the automatic event reporting globally?" icon="signal-stream-slash">
  To disable automatic event reporting for all endpoints by default, set `events: { sendAutomatically: false }` in the `defaultMiddlewareOptions` when initializing the Atlas Express Client. This is useful if you plan to report most events manually.

  ```typescript src/index.ts [expandable] {8-12} theme={null}
  import { AtlasExpressClient } from "@runonatlas/express";
  import express from "express";
  import { getAuth } from "@clerk/express";

  const app = express();
  const atlas = new AtlasExpressClient((req) => getAuth(req).userId, {
    defaultMiddlewareOptions: {
      events: { sendAutomatically: false },
    },
  });
  ```
</Accordion>

### Batching events

To optimize performance and avoid rate limits, the Atlas client automatically batches usage events before sending them. You can customize this batching behavior by configuring the `eventsFlushAt` (number of events) and `eventsFlushInterval` (time in milliseconds) options during client initialization.

```typescript src/index.ts [expandable] {9-11} theme={null}
import { AtlasExpressClient } from "@runonatlas/express";
import express from "express";
import { getAuth } from "@clerk/express";

const app = express();
const atlas = new AtlasExpressClient((req) => getAuth(req).userId, {
  // Events will be sent every 10 events or every 1 second, whichever comes first.
  eventsFlushAt: 10,
  eventsFlushInterval: 1000,
});
```

You can also trigger a manual flush of all enqueued events at any time using the `flushEvents` method. This is particularly useful for ensuring no events are lost during a graceful shutdown of your application.

```typescript src/index.ts [expandable] {11} theme={null}
async function onProcessShutdown() {
  await atlas.client.flushEvents();
}
```

## Organizations

<Warning>
  This only covers the backend configuration. You will also need to configure
  your frontend. For example,
  [React](/developer-portal/sdk/react?#organizations) or
  [Next.js](/developer-portal/sdk/next?#organizations).
</Warning>

In many applications, it's common to allow multiple users to belong to the same organization and share a single subscription. For example: Alice creates an organization called **Standard Corp**, purchases a plan, and invites Bob and Carol to join. Since all three are members of the same organization, they should share access to the same plan and limits.

To enable this, you should use the **organization ID** as the user identifier instead of the individual user ID. This tells Atlas that access and usage should be scoped to the organization — not the individual — ensuring that Bob and Carol both have access under Standard Corp’s plan.

<CodeGroup>
  ```typescript src/index.ts [expandable] {7} theme={null}
  import { AtlasExpressClient } from "@runonatlas/express";
  import { getAuth } from "@clerk/express";
  import express from "express";

  const app = express();
  const atlas = new AtlasExpressClient(
    (req) => getAuth(req).orgId
  );

  app.use("/", atlas.router);

  ```
</CodeGroup>

```
```
