# You can specify the URL of your development `serve` API endpoint
npx --ignore-scripts=false inngest-cli@latest dev -u http://localhost:3000/api/inngest
```
```shell {{ title: "Docker" }}
docker run -p 8288:8288 inngest/inngest \
  inngest dev -u http://host.docker.internal:3000/api/inngest
```
</CodeGroup>

You can now open the dev server's browser interface on [`http://localhost:8288`](http://localhost:8288).

## Connecting apps to the Dev Server

There are two ways to connect apps to the Dev Server:

1. **Automatically**: The Dev Server will attempt to "auto-discover" apps running on common ports and endpoints (See "[Auto-discovery](#auto-discovery)").
2. **Manually**: You scan explicitly add the URL of the app to the Dev Server using one of the following options:
    - Using the CLI `-u` param (ex. `npx --ignore-scripts=false inngest-cli@latest dev -u http://localhost:3000/api/inngest`)
    - Adding the URL in the Dev Server Apps page. You can edit the URL or delete a manually added app at any point in time
    - Using the `inngest.json` (or similar) configuration file (See "[Configuration file](#configuration-file)")

![Dev Server demo manually syncing an app](/assets/docs/local-development/dev-server-apps-demo-2025-01-15.gif)

<Tip>
  The dev server does "auto-discovery" which scans popular ports and endpoints like `/api/inngest` and `/.netlify/functions/inngest`. **If you would like to disable auto-discovery, pass the `--no-discovery` flag to the `dev` command**. Learn more about [this below](#auto-discovery)
</Tip>

### How functions are loaded by the Dev Server

The dev server polls your app locally for any new or changed functions. Then as events are sent, the dev server calls your functions directly, just as Inngest would do in production over the public internet.

[IMAGE]

## Testing functions

### Invoke via UI

From the Functions tab, you can quickly test any function by click the "Invoke" button and providing the data for your payload in the modal that pops up there. This is the easiest way to directly call a specific function:

[IMAGE]

### Sending events to the Dev Server

There are different ways that you can send events to the dev server when testing locally:

1. Using the Inngest SDK
2. Using the "Test Event" button in the Dev Server's interface
3. Via HTTP request (e.g. curl)

#### Using the Inngest SDK

When using the Inngest SDK locally, it tries to detect if the dev server is running on your machine. If it's running, the event will be sent there.

<CodeGroup>
```ts {{ title: "Node.js" }}
new Inngest({ id: "my_app" });
await inngest.send({
  name: "user.avatar.uploaded",
  data: { url: "https://a-bucket.s3.us-west-2.amazonaws.com/..." },
});
```

```python {{ title: "Python" }}
from inngest import Inngest

inngest_client = inngest.Inngest(app_id="my_app")
await inngest_client.send(
  name="user.avatar.uploaded",
  data={"url": "https://a-bucket.s3.us-west-2.amazonaws.com/..."},
)
```

```go {{ title: "Go" }}
!snippet:path=snippets/go/docs/examples/devserver/main.go
```
</CodeGroup>
**Note** - During local development, you can use a dummy value for your [`INNGEST_EVENT_KEY`](/docs/sdk/environment-variables#inngest-event-key?ref=local-development) environment variable. The dev server does not validate keys locally.

#### Using the "Test Event" button

The dev server's interface also has a "Test Event" button on the top right that enables you to enter any JSON event payload and send it manually. This is useful for testing out different variants of event payloads with your functions.

[IMAGE]

#### Via HTTP request

All events are sent to Inngest using a simple HTTP API with a JSON body. Here is an example of a curl request to the local dev server's `/e/<EVENT_KEY>` endpoint running on the default port of `8228` using a dummy event key of `123`:

```shell
curl -X POST -v "http://localhost:8288/e/123" \
  -d '{
    "name": "user.avatar.uploaded",
    "data": { "url": "https://a-bucket.s3.us-west-2.amazonaws.com/..." }
  }'
```

<Callout>
  💡 Since you can send events via HTTP, this means you can send events with any programming language or from your favorite testing tools like Postman.
</Callout>

## Configuration file

When using lots of configuration options or specifying multiple `-u` flags for a project, you can choose to configure the CLI via `inngest.json` configuration file. The `dev` command will start in your current directory and walk up directories until it finds a file. `yaml`, `yml`, `toml`, or `properties` file formats and extensions are also supported. You can list all options with `dev --help`. Here is an example file specifying two app urls and the `no-discovery` option:

<CodeGroup>
```json {{ title: "inngest.json" }}
{
  "sdk-url": [
    "http://localhost:3000/api/inngest",
    "http://localhost:3030/api/inngest"
  ],
  "no-discovery": true
}
```
```yaml {{ title: "inngest.yaml" }}
sdk-url:
  - "http://localhost:3000/api/inngest"
  - "http://localhost:3030/api/inngest"
no-discovery: true
```
</CodeGroup>

## Inngest SDK debug endpoint

The [SDK's `serve` API endpoint](/docs/learn/serving-inngest-functions) will return some diagnostic information for your server configuration when sending a `GET` request. You can do this via `curl` command or by opening the URL in the browser.

Here is an example of a curl request to an Inngest app running at `http://localhost:3000/api/inngest`:

```sh
$ curl -s http://localhost:3000/api/inngest | jq
{
  "message": "Inngest endpoint configured correctly.",
  "hasEventKey": false,
  "hasSigningKey": false,
  "functionsFound": 1
}
```

## Auto-discovery

The dev server will automatically detect and connect to apps running on common ports and endpoints. You can disable auto-discovery by passing the `--no-discovery` flag to the `dev` command:

```sh
npx --ignore-scripts=false inngest-cli@latest dev --no-discovery -u http://localhost:3000/api/inngest
```

<CodeGroup>
```plaintext {{ title: "Common endpoints" }}
/api/inngest
/x/inngest
/.netlify/functions/inngest
/.redwood/functions/inngest
```

```plaintext {{ title: "Common ports" }}
80, 443,
// Rails, Express & Next/Nuxt/Nest routes
3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010,
// Django
5000,
// Vite/SvelteKit
5173,
// Other common ports
8000, 8080, 8081, 8888,
// Redwood
8910, 8911, 8912, 8913, 8914, 8915,
// Cloudflare Workers
8787,
```
</CodeGroup>

## CLI flags

`inngest-cli dev` command supports the following flags:

| **Long form**  | **Short form** | **Type** | **Default value**                 | **Description**                       |
|:--------------:|:--------------:|:--------:|:---------------------------------:|:-------------------------------------:|
| --config       | -              | string   | -                                 | Path to an Inngest configuration file |
| --help         | -h             | -        | -                                 | Output the help information           |
| --host         | -              | string   | http://localhost                  | Inngest server host                   |
| --no-discovery | -              | boolean  | false                             | Disable app auto-discovery            |
| --no-poll      | -              | boolean  | false                             | Disable polling of apps for updates   |
| --port         | -p             | int      | 8288                              | Inngest server port                   |
| --sdk-url      | -u             | strings  | http://localhost:3000/api/inngest | App serve URLs to sync                |

## Development with Docker

Inngest provides a Docker image that you can use to run the Inngest Dev Server within a container. This is useful when running Inngest locally or in a CI/CD environment.

### Docker image

The [`inngest/inngest`](https://hub.docker.com/r/inngest/inngest) image is available on Docker Hub. Regular updates are made to this image, so we recommend pulling the latest version. You can find the latest version release on [our Github repo](https://github.com/inngest/inngest/releases).

```bash
docker pull inngest/inngest
```

### Standalone Docker container

Docker can be useful for running the Inngest Dev Server in a standalone container. This is useful if you do not want to use the `npx --ignore-scripts=false inngest-cli@latest` method to run the Dev Server.

To run the Inngest container, you'll need to:

1. Expose the Dev Server port (default is `8288`).
2. Use the `inngest dev` command with the `-u` flag to specify the URL where Inngest can find your app.

In this example command, our app is running on the host machine on port `3000`. We use the `host.docker.internal` hostname to connect to the host machine from within the Docker container. For ease of reading, the command is broken up into multiple lines.

```bash
docker run -p 8288:8288 \
  inngest/inngest \
  inngest dev -u http://host.docker.internal:3000/api/inngest
```

You will then be able to access the Inngest Dev Server on your host machine at `http://localhost:8288` or whatever hostname you have configured. You may need to adjust the hostname for your app if you are using a different Docker network setup.

<Callout>
  If you decide to run the Dev Server on another port, you will need to set the `INNGEST_BASE_URL` environment variable in your app to point to the correct port. This value defaults to `http://localhost:8288`.
</Callout>

### Docker Compose

If you're using [Docker Compose](https://docs.docker.com/compose/) to run your services locally, you can easily add Inngest to your local environment. Here's an example `docker-compose.yml` file that includes Inngest:

```yaml {{ filename: "docker-compose.yaml" }}
services:
  app:
    build: ./app
    environment:
      - INNGEST_DEV=1
      - INNGEST_BASE_URL=http://inngest:8288
    ports:
      - '3000:3000'
  inngest:
    image: inngest/inngest:v0.27.0
    command: 'inngest dev -u http://app:3000/api/inngest'
    ports:
      - '8288:8288'
```

In this example, we have two services: `app` and `inngest`. The `app` service is your application, and the `inngest` service is the Inngest Dev Server. There are a few key configurations to note:

* The `INNGEST_DEV=1` environment variable tells the Inngest SDK it should connect to the Dev Server*.
* The `INNGEST_BASE_URL=http://inngest:8288` environment variable tells the Inngest SDK where the Dev Server is running. In our example, the `inngest` service is running on port `8288` (the default Dev Server port).
* The `command: 'inngest dev -u http://app:3000/api/inngest'` command tells the Dev Server where to find your app within the Docker network. In this example, the `app` service is running on port `3000`.
* The `ports` configuration exposes the Dev Server on port `8288` so you can view this on your host machine in the browser.

\* - The `INNGEST_DEV` environment variable was added to the TypeScript SDK in version 3.14. Prior to this version, you can set `NODE_ENV=development` to force the SDK to connect to the Dev Server.

## Development flow

Developing with Inngest looks as it follows:

1. Configure the Inngest SDK in your application
2. [Connecting the Inngest Dev Server to your local application](#connecting-apps-to-the-dev-server)
3. Develop your Inngest Functions with [Steps](/docs/learn/inngest-steps), [Flow Control](/docs/guides/flow-control) and [more](/docs/learn/inngest-functions)
5. _(Optional) - Configure Preview environments with [our Vercel Integration](/docs/deploy/vercel)_

<ImageTheme
  dark={'/assets/docs/features/local-development/Durable-Execution-Engine-local-dev-dark.jpg'}
  light={'/assets/docs/features/local-development/Durable-Execution-Engine-local-dev-light.jpg'}
  className="my-0"
  alt={'The Inngest Dev Server runs locally on your machine and communicates with your local application.'}
/>

**Moving to production environments (preview envs, staging or production)**

Deploying your application to preview, staging and production environments does not require any code change:

6. [Create an Inngest App](/docs/apps) on the Inngest Platform and [configure its Event and Signing Keys on your Cloud](/docs/platform/deployment).
7. Leverage the Inngest Platform to manage and monitor Events and Function Runs

<ImageTheme
  dark={'/assets/docs/features/local-development/Durable-Execution-Engine-staging-prod-dark.jpg'}
  light={'/assets/docs/features/local-development/Durable-Execution-Engine-staging-prod-light.jpg'}
  className="my-0"
  alt={'When deployed, your application communicates with the Inngest Platform.'}
/>

## SDKs

<CardGroup cols={1}>
  <Card title="TypeScript SDK" icon={<TypeScriptIcon className="text-basis"/>} href={'/docs/reference/typescript'}>
    Setup the Inngest SDK in your TypeScript application.
  </Card>
  <Card title="Python SDK" icon={<PythonIcon className="text-basis"/>} href={'/docs/reference/python'}>
    Setup the Inngest SDK in your Python application.
  </Card>
  <Card title="Go SDK" icon={<GoIcon className="text-basis"/>} href={'https://pkg.go.dev/github.com/inngest/inngestgo'}>
    Setup the Inngest SDK in your Go application.
  </Card>
</CardGroup>

## FAQs

<CardGroup cols={1}>
  <Card title="Can I run the Inngest Dev Server in production?" icon={<RiQuestionLine />}>
    The Inngest Dev Server is not designed to be run in production, but you can run it anywhere that you want including testing environments or CI/CD pipelines.
  </Card>
  <Card title="How do I test webhooks locally?" icon={<RiQuestionLine />}>
    Webhooks configured on the Platform [can be sent to the Dev Server](/docs/platform/webhooks#local-development).
  </Card>
  <Card title="How do I work with Stripe or Clerk webhooks locally?" icon={<RiQuestionLine />}>
    External webhooks from Stripe and Clerk must go through a tunnel solution (such as [ngrok](https://ngrok.com/) or [localtunnel](https://theboroer.github.io/localtunnel-www/)) to reach the Dev Server.
  </Card>
  <Card title="Are Crons supported locally?" icon={<RiQuestionLine />}>
    Yes. You can also trigger a function at any time by using the "Invoke" button from the Dev Server Functions list view.
  </Card>
</CardGroup>

Find more answers in our [Discord community](/discord).

## Further reference

* [Dev Server source code on GitHub](https://github.com/inngest/inngest)
* [`inngest/inngest` Docker image on Docker Hub](https://hub.docker.com/r/inngest/inngest)
* [TypeScript SDK Environment variable reference](/docs/sdk/environment-variables)
* [Python SDK Environment variable reference](/docs/reference/python/overview/env-vars)