# Develop and test a function locally

You can run a [function](/en/documentation/platform/functions/) on your own machine with [Azion CLI](/en/documentation/devtools/cli/) and send it real requests before deploying. The `azion dev` command starts a local development server for the current project. You read the response your code returns without deploying it first.

---

## Prerequisites

- [Azion CLI](/en/documentation/devtools/cli/) installed, and a personal token saved with `azion -t <your-token>`.
- A project on your machine. To create one, run `azion init` and select the **Javascript** preset.

---

## Run the function locally

`azion dev` builds the project and serves it from your machine. To start the server:

```bash
azion dev
```

The command builds the project first, then prints the address it is serving on:

```bash
[Azion Bundler] [Server] › ✔  success   Function running on port http://localhost:3000
```

Use the address the command prints. To choose the port yourself, pass `--port`:

```bash
azion dev --port 4000
```

With the server running, send the function a request from another terminal:

```bash
curl http://localhost:3000/
```

The response your handler returns appears in the terminal. Anything the code writes with `console.log()` appears in the terminal running `azion dev`.

---

## Provide environment variables locally

A function reads a variable with `Azion.env.get()`, which takes the key and returns the value:

```js
export default {
  async fetch(request, env, ctx) {
    const message = Azion.env.get('GREETING_MESSAGE') || 'Default value';

    return new Response(message, {
      headers: { 'content-type': 'text/plain' }
    });
  }
};
```

The `|| 'Default value'` fallback matters locally: `Azion.env.get()` returns `undefined` for a key that is not set. A handler that reads a variable directly into a response then returns the string `undefined` instead of failing. Give every variable a fallback, and the function runs before any variable exists.

Keep local values in a `.env` file next to the project, one `KEY="value"` pair per line:

```bash
GREETING_MESSAGE="Hello from your machine"
```

`azion deploy` reads `.edge/.env` by default. To point it at a different file, pass `--env`:

```bash
azion deploy --env .env
```

Never commit a file that holds real credentials. Keep a `.env.example` with the keys and placeholder values in version control, and keep the real `.env` out of it.

---

## Choose where to test a function

Three surfaces run a function before it serves production traffic, and they answer different questions.

| Surface                                                                        | Where it runs                     | Reach for it when                                                                                                                             |
| ------------------------------------------------------------------------------ | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| Local development                                                              | Your machine, through `azion dev` | You are iterating on code, want real requests with your own headers and bodies, and want the edit-run loop to be fast                         |
| [Preview deployment](/en/documentation/platform/functions/preview-deployment/) | Azion Console                     | You are working in the Console and want to read the response to one simulated request, built by `PreviewProvider`, without leaving the editor |
| [Code editor](/en/documentation/platform/functions/code-editor/)               | Azion Console                     | You are writing or correcting the code itself and want syntax highlighting and IntelliSense                                                   |

Local development is the only one of the three that accepts a request you compose yourself. It is where you exercise a handler across methods, headers, and bodies. Preview deployment sends one simulated request and renders the response.

---

## Next steps

- [Deploy a function with Azion CLI](/en/documentation/guides/application-development/functions-and-runtime/deploy-function-with-cli.md): Take the project you just ran locally and deploy it from the terminal.
- [Environment variables](/en/documentation/platform/functions/environment-variables.md): The fields, the caps, and the interfaces that create a variable on the account.
- [Azion CLI dev](/en/documentation/devtools/cli/dev-command.md): Every flag the dev command accepts.
- [Troubleshoot function execution and logs](/en/documentation/platform/functions/troubleshooting.md): Read the log output of a function once it is deployed.
