# Self-hosting

Self-hosting support for Inngest is supported as of the 1.0 release.

- [Why self-host Inngest?](#why-self-host-inngest)
- [Inngest system architecture](#inngest-system-architecture)
- [How to self-host Inngest](#how-to-self-host-inngest)

> **Info:** Inngest's support team does not guarantee direct support for self-hosted instances. If you need help, please file an issue.
> &#x20;If you require dedicated support or service guarantees for self-hosting, please contact us to explore enterprise options.

## Why self-host Inngest?

While the easiest way to get started with Inngest is using our hosted platform, including our generous [free tier](/pricing?ref=docs-self-hosting), we understand that developers may want to self-host for a variety of reasons. If security or data privacy are concerns, review our [security documentation](/docs-markdown/learn/security?ref=docs-self-hosting) for more information including details about [end-to-end encryption](/docs-markdown/features/middleware/encryption-middleware?ref=docs-self-hosting).

## Inngest system architecture

To best understand how to self-host Inngest, it's important to understand the system architecture and components.

![Inngest system architecture diagram](/assets/docs-markdown/self-hosting/system-architecture-2024-09-23.png)

The system is composed of the following services:

- **Event API** - Receives events from SDKs via HTTP requests. Authenticates client requests via [Event Keys](/docs-markdown/events/creating-an-event-key?ref=docs-self-hosting). The Event API publishes event payloads to an internal event stream.
- **Event stream** - Acts as a buffer between the *Event API* and the *Runner*.
- **Runner** - Consumes incoming events and performs several actions:
  - Scheduling of new "function runs" (aka jobs) given the event type, creating initial run state in the *State store* database. Runs are added to queues given the function's flow control configuration.
  - Resumes functions paused via [`waitForEvent`](/docs-markdown/features/inngest-functions/steps-workflows/wait-for-event?ref=docs-self-hosting) with matching expressions.
  - Cancels running functions with matching [`cancelOn`](/docs-markdown/features/inngest-functions/cancellation/cancel-on-events?ref=docs-self-hosting) expressions.
  - Writes ingested events to a database for historical record and future replay.
- **Queue** - A multitenant-aware, multitier queue designed for fairness and various [flow control](/docs-markdown/guides/flow-control?ref=docs-self-hosting) methods (concurrency, throttling, prioritization, debouncing, rate limiting) and [batching](/docs-markdown/guides/batching?ref=docs-self-hosting).
- **Executor** - Responsible for executing functions, from initial execution, step execution, writing incremental function run state to the *State store*, and retries after failures.
- **State store (database)** - Persists data for pending and ongoing function runs. Data includes initial triggering event(s), step output and step errors.
- **Database** - Persists system data and history including Apps, Functions, Events, Function run results.
- **API** - GraphQL and REST APIs for programmatic access and management of system resources.
- **Dashboard UI** - The UI to manage apps, functions and view function run history.

The source code for Inngest and all services is [available on GitHub](https://github.com/inngest/inngest).

## How to self-host Inngest

To begin self-hosting Inngest, you only need to install the Inngest CLI. The Inngest CLI is a single binary that includes all Inngest services and can be run in any environment. Alternatively, you can download the binary directly from [GitHub releases](https://github.com/inngest/inngest/releases).

```plaintext {{ title: "Docker" }}
docker pull inngest/inngest
```

```plaintext {{ title: "npm" }}
npm install -g inngest-cli
```

```plaintext {{ title: "curl" }}
curl -sfL https://cli.inngest.com/install.sh
```

Now that you have the CLI installed, you can start the Inngest server using the `inngest start` command.

```plaintext {{ title: "Docker" }}
docker run -p 8288:8288 -p 8289:8289 -e INNGEST_EVENT_KEY=abcd -e INNGEST_SIGNING_KEY=1234 inngest/inngest inngest start
```

```plaintext {{ title: "shell" }}
inngest start --event-key abcd --signing-key 1234
```

This will start the Inngest server on the default port `8288` and use the default configuration, including SQLite for persistence. Additionally, the Connect gateway will be available on port `8289`.

### Configuration

Configuring the server can be done via command-line flags, environment variables, or a configuration file.

By default, the server will:

- Run on `localhost:8288` to serve the Event API, API, and Dashboard UI. `localhost:8289` is used for `connect` workers ([see docs for more connect-specific configuration](/docs-markdown/setup/connect#self-hosted-inngest)).
- Use an in-memory Redis server for the queue and state store. (See [Using external services](#using-external-services) for more information.)
- Use SQLite for persistence. The default database is located at `./.inngest/main.db`. Queue and state store snapshots are periodically saved to the SQLite database, including prior to shutdown.
- Disable app sync polling to check for new functions or updated configurations (see `--poll-interval` flag).

To securely configure your server, create your event and signing keys using whatever format you choose and start the Inngest server using them. You can also pass them via environment variable (see below):

> **Callout:** The signing key must be a valid hexadecimal string with an even number of characters. You can generate a secure signing key using:openssl rand -hex 32

```plaintext
inngest start --event-key <YOUR_EVENT_KEY> --signing-key <YOUR_SIGNING_KEY>
```

Then you can use these same keys as environment variables when starting your application (`INNGEST_EVENT_KEY` and `INNGEST_SIGNING_KEY`). [See below](#configuring-inngest-sdks-to-use-self-hosted-server) for an example Node.js startup command.

To see all the available options, run `inngest start --help`:

```
$ inngest start --help
NAME:
   inngest start - [Beta] Run Inngest as a single-node service.

USAGE:
   inngest start [options]

DESCRIPTION:
   Example: inngest start

OPTIONS:
   --config string                                              Path to an Inngest configuration file
   --event-key string [ --event-key string ]                    Event key(s) that will be used by apps to send events to the server.
   --help, -h                                                   show help
   --host string                                                Inngest server hostname
   --port string, -p string                                     Inngest server port (default: "8288")
   --sdk-url string, -u string [ --sdk-url string, -u string ]  App serve URLs to sync (ex. http://localhost:3000/api/inngest)
   --signing-key string                                         Signing key used to sign and validate data between the server and apps. Must be hex string with even number of chars

   Advanced

   --connect-gateway-port int  Port to expose connect gateway endpoint (default: 8289)
   --no-ui                     Disable the web UI and GraphQL API endpoint (default: false)
   --poll-interval int         Interval in seconds between polling for updates to apps (default: 0)
   --queue-workers int         Number of executor workers to execute steps from the queue (default: 100)
   --retry-interval int        Retry interval in seconds for linear backoff when retrying functions - must be 1 or above (default: 0)
   --tick int                  The interval (in milliseconds) at which the executor polls the queue (default: 150)

   Persistence

   --postgres-conn-max-idle-time int  Sets the maximum amount of time, in minutes, a PostgreSQL connection may be idle. (default: 5)
   --postgres-conn-max-lifetime int   Sets the maximum amount of time, in minutes, a PostgreSQL connection may be reused. (default: 30)
   --postgres-max-idle-conns int      Sets the maximum number of idle database connections in the PostgreSQL connection pool. (default: 10)
   --postgres-max-open-conns int      Sets the maximum number of open database connections allowed in the PostgreSQL connection pool. (default: 100)
   --postgres-uri string              PostgreSQL database URI for configuration and history persistence. Defaults to SQLite database.
   --redis-uri string                 Redis server URI for external queue and run state. Defaults to self-contained, in-memory Redis server with periodic snapshot backups.
   --sqlite-dir string                Directory for where to write SQLite database.

GLOBAL OPTIONS:
   --json                         Output logs as JSON.  Set to true if stdout is not a TTY. (default: false)
   --verbose                      Enable verbose logging. (default: false)
   --log-level string, -l string  Set the log level.  One of: trace, debug, info, warn, error. (default: "info")
```

**Environment variables**

Any CLI option can be set via environment variable by converting the flag to uppercase, replacing hyphens with underscores, and prefixing it with `INNGEST_`. For example, `--port 8288` can be set with the `INNGEST_PORT` environment variable.

To set the log level, use `LOG_LEVEL=WARN` or whatever level you choose. This environment variable does not use the Inngest prefix. The environment variable will always take precedence over the CLI `--log-level` flag.

**Configuration file** (`inngest.yaml`, `inngest.json`, etc.)

A configuration file can be specified with the `--config` flag. The file can be in YAML, JSON, TOML, or any other format supported by [Viper](https://github.com/spf13/viper). `urls` is used instead of `sdk-url` to specify your application's Inngest serve endpoints. An example configuration file is shown below:

```yaml {{ title: "inngest.yaml" }}
urls:
  - http://localhost:3000/api/inngest
poll-interval: 60
redis-uri: redis://localhost:6379
sqlite-dir: /app/data
```

```json {{ title: "inngest.json" }}
{
  "urls": [
    "http://localhost:3000/api/inngest"
  ],
  "poll-interval": 60,
  "redis-uri": "redis://localhost:6379",
  "sqlite-dir": "/app/data"
}
```

Note, configuring the log level can only be currently done via flag or environment variable.

### Configuring Inngest SDKs to use self-hosted server

By default, the Inngest SDK will use URLs of the managed Inngest platform. To connect to a self-hosted server, set the [`INNGEST_DEV`](/docs-markdown/sdk/environment-variables#inngest-dev) and [`INNGEST_BASE_URL`](/docs-markdown/sdk/environment-variables#inngest-base-url) environment variables. As mentioned above, you'll also need to set the `INNGEST_EVENT_KEY` and `INNGEST_SIGNING_KEY` environment variables for securely connecting your application to the Inngest server.

For example, to connect to a self-hosted server running on `localhost:8288` for a Node.js app, set the following environment variables:

```plaintext
INNGEST_EVENT_KEY=<YOUR_EVENT_KEY> \
  INNGEST_SIGNING_KEY=<YOUR_SIGNING_KEY> \
  INNGEST_DEV=0 \
  INNGEST_BASE_URL=http://localhost:8288 \
  node ./server.js
```

### Using external services

Inngest can be configured to use external services for the queue and state store, and soon, the database.

**External Redis server**

With the goal of simplifying the initial setup, the Inngest server will run an in-memory Redis server for the queue and state store. As this is running within the same process as the Inngest server, running your own Redis server can improve performance and reliability of the system. You may choose to run your own Redis server or use a cloud-based Redis service like AWS ElastiCache, Redis Cloud, etc.

To use an external Redis server, set the `redis-uri` flag to the Redis server URI.

**External Postgres database**

By default, the Inngest server uses SQLite for persistence. This is convenient for zero-dependency deployments, but does not support scaling beyond a single node. You may choose to run your own Postgres database or use a cloud-based Postgres service like AWS RDS, Neon, Supabase, etc.

To use an external Postgres database, set the `postgres-uri` flag to your Postgres connection string URI.

## Docker compose example

```yaml
services:
  inngest:
    image: inngest/inngest
    command: "inngest start"
    ports:
      - "8288:8288" # APIs and Dashboard
      - "8289:8289" # Connect WebSocket gateway
    environment:
      - INNGEST_EVENT_KEY=your_event_key_here # Must be hex string with even number of chars
      - INNGEST_SIGNING_KEY=your_signing_key_here # Must be hex string with even number of chars
      - INNGEST_POSTGRES_URI=postgres://inngest:password@postgres:5432/inngest
      - INNGEST_REDIS_URI=redis://redis:6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - inngest-network
    healthcheck:
      test: ["CMD", "inngest", "alpha", "doctor", "healthcheck"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  postgres:
    image: postgres:17
    environment:
      - POSTGRES_DB=inngest
      - POSTGRES_USER=inngest
      - POSTGRES_PASSWORD=password
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - inngest-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U inngest -d inngest"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    networks:
      - inngest-network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

volumes:
  postgres_data:
  redis_data:

networks:
  inngest-network:
    driver: bridge

```

**Note**: The `inngest alpha doctor` command was added in `v1.19.3`, before this version, you can define a healthcheck using `test: ["CMD", "curl", "-f", "http://localhost:8288/health"]`

## Helm chart

Inngest provides a Helm chart for production-ready Kubernetes deployments. Key features include:

**Quick Setup & Production Ready**

- Installable from OCI Registry ([see docs](https://github.com/inngest/inngest-helm?tab=readme-ov-file#installation))
- Supports Kubernetes 1.20+ and Helm 3.0+ with simple installation
- Bundled PostgreSQL and Redis for easy setup, with support for external databases
- Consistent resource naming across all environments regardless of Helm release name
- Deployment examples for development, production, and hybrid scenarios

**Autoscaling & Performance**

- KEDA-based autoscaling using Inngest's Prometheus metrics
- Configurable replica counts, resource limits, and queue worker settings
- Horizontal pod autoscaling based on queue depth

**Security & Access**

- Security-first design with non-root execution and read-only filesystem
- Database credentials stored securely in Kubernetes Secrets
- Network policy support for additional cluster isolation
- Built-in ingress support with SSL certificate provisioning via cert-manager
- Let's Encrypt integration for production HTTPS endpoints

You can find the chart, documentation, and configuration examples here:

**inngest/inngest-helm**: [View source code, check release notes and file issues.]('https://github.com/inngest/inngest-helm')

## Prometheus metrics&#x20;

Inngest exposes a Prometheus-compatible scrape endpoint at `GET /metrics` on the server port (e.g. `http://localhost:8288/metrics`). By default it emits a single gauge, `inngest_queue_depth`. To enable per-function lifecycle counters (`inngest_function_run_*_total`, `inngest_sdk_req_*_total`), start the server with the experimental flag enabled: `INNGEST_EXPERIMENTAL_PROM_METRICS=1`. Point your Prometheus scrape config at the `/metrics` path on that port — no auth is configured by default.

## Roadmap & feature requests

Planned features for self-hosting include:

- Improved diagnostic checks and APIs (via `inngest alpha doctor` and `inngest alpha debug` - currently in alpha)

To suggest additional features, report issues, submit pull requests, and view the source code please visit the repo on GitHub:

**inngest/inngest**: [View source code, check release notes and file issues.]('https://github.com/inngest/inngest')