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

> ## Agent Instructions
> These are the docs for Sevalla, a platform for deploying applications, databases, static sites, object storage and load balancers. The dashboard is at https://app.sevalla.com.
> Bold text in steps is an exact dashboard label.
> To act on a Sevalla account, prefer the Sevalla MCP server (https://mcp.sevalla.com/mcp, see https://docs.sevalla.com/ai-agents/overview.md), then the Sevalla CLI (https://docs.sevalla.com/developer-tools/cli.md), then the REST API (https://api-docs.sevalla.com, OpenAPI spec at https://api.sevalla.com/v3/openapi.json).
> Every page index is at https://docs.sevalla.com/llms.txt.

# Use Redis from Node.js

> Connect a Node.js application on Sevalla to a Redis or Valkey database over an internal connection, and cache responses with ioredis using the REDIS_* variables.

A Node.js application on Sevalla reaches a Redis or Valkey database over an internal connection: the connection adds the database's host, port and password to the application as environment variables, and ioredis connects with them over the private network. This guide caches a slow response in Redis from an Express application. Because every instance and process of the application shares the database, the cache, sessions and queues you keep there work with more than one instance.

## Before you begin

* An Express application deployed on Sevalla, as in [Deploy Express](/guides/javascript/express).
* Node.js 20 or later in the application, which ioredis 6 needs. The Express guide pins Node.js 24.

## Create a Redis database

<Steps>
  <Step title="Create the database">
    In the sidebar, click **Databases**, then click **Create database**. Under **Database**, choose **Redis** or **Valkey** and the version. Enter `storefront-redis` as the **Display name**, choose the same **Data center** as the application and a **Size**, then click **Create database**. See [Create a database](/databases/create) for every field.
  </Step>

  <Step title="Connect it to the application">
    In the sidebar, click **Applications**, then click the application. Click the **Networking** tab. Under **Connected services**, click **Add internal connection**. Choose `storefront-redis` as the **Service**, turn on **Add environment variables to the application**, and click **Add internal connection**. Only services in the application's location are listed.
  </Step>
</Steps>

The connection adds four variables to the application, which apply at the next deployment:

| Variable | Value |
| - | - |
| `REDIS_HOST` | The database's internal hostname |
| `REDIS_PORT` | The database's internal port |
| `REDIS_PASSWORD` | The database's password |
| `REDIS_URL` | The internal connection URL, such as `redis://:<password>@<host>:<port>/0` |

Redis and Valkey databases have a password but no username, and clients use logical database `0`. See [Connect an application](/databases/connect#connect-an-application).

## Install ioredis

```bash theme={null}
npm install ioredis
```

## Create the client

Create one client for the whole application, from the separate variables:

```js redis.js theme={null}
import { Redis } from "ioredis";

export const redis = new Redis({
  host: process.env.REDIS_HOST,
  port: Number(process.env.REDIS_PORT),
  password: process.env.REDIS_PASSWORD,
});
```

The separate variables work for both engines. For a Valkey database, `REDIS_URL` starts with `valkey://`, which ioredis doesn't parse as a URL. For a Redis database, `new Redis(process.env.REDIS_URL)` works too.

ioredis reconnects on its own when the connection drops, and queues commands until it's back.

## Cache a slow response

Add a route to `server.js` that keeps its result in Redis for 60 seconds:

```js server.js theme={null}
import express from "express";
import { redis } from "./redis.js";

const app = express();
const port = process.env.PORT || 3000;

// Stands in for a slow database query or API call.
async function loadProducts() {
  await new Promise((resolve) => setTimeout(resolve, 1000));
  return [{ id: 1, name: "Coffee mug" }];
}

app.get("/products", async (req, res) => {
  const cached = await redis.get("products");
  if (cached) {
    res.set("X-Cache", "hit").type("json").send(cached);
    return;
  }

  const products = await loadProducts();
  await redis.set("products", JSON.stringify(products), "EX", 60);
  res.set("X-Cache", "miss").json(products);
});

const server = app.listen(port, () => {
  console.log(`Listening on port ${port}`);
});

// Finish open requests and close the Redis connection when Sevalla stops the instance.
process.on("SIGTERM", () => {
  server.close(async () => {
    await redis.quit();
    process.exit(0);
  });
});
```

`EX 60` makes Redis delete the key after 60 seconds, so the next request loads fresh data. Delete the key with `redis.del("products")` when the data changes.

## Deploy and verify

Commit and push the changes. With auto-deploy on, the push starts a deployment; otherwise, start one with **Deploy now** on the application's **Overview** tab. The deployment also gives the application the variables the internal connection added. When the deployment's status changes to **Deployed**:

1. Request the route twice:

   ```bash theme={null}
   curl -i https://storefront-x7k2m.sevalla.app/products
   curl -i https://storefront-x7k2m.sevalla.app/products
   ```

   The first response has `X-Cache: miss` and takes about a second. The second has `X-Cache: hit` and returns at once.
2. On the database's **Redis studio** tab, the `products` key appears with its value until it expires. See [Database studio](/databases/studio).

If the requests fail, read the application's [runtime logs](/applications/logs):

| Log message | Cause | Fix |
| - | - | - |
| `connect ECONNREFUSED 127.0.0.1:6379` | `REDIS_HOST` isn't set, so ioredis tries `localhost` | Add the internal connection with **Add environment variables to the application** turned on, then deploy. |
| `NOAUTH Authentication required` or `WRONGPASS` | `REDIS_PASSWORD` is missing or old | The variables are copies: after you [change the database password](/databases/connect#change-the-database-password), update `REDIS_PASSWORD` and `REDIS_URL` and deploy. |

## Use Redis from other processes

Environment variables belong to the application, so its [background workers and cron jobs](/applications/processes) get the same `REDIS_*` variables as the web process. Import the same `redis.js` in a worker to process a queue, or store sessions in Redis with your framework's Redis session store so that a visitor stays signed in on every instance.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.