# Azion CLI quickstart

This guide instructs you through your first deployment with the Azion CLI.

- Install the CLI and save your personal token in it.
- Create a JavaScript function project with `azion init`.
- Run the function on your machine with `azion dev`.
- Deploy the function with `azion deploy` and request it over HTTPS.

The `azion deploy` command creates five objects from the project, and each one links to the next:

1. The **function** holds the code in `src/function/index.js`.
2. The **function instance** binds the function to the application.
3. The [application](/en/documentation/platform/applications/) carries a request rule, `Execute Function`, that runs the instance on every path.
4. The [workload](/en/documentation/platform/workloads/) serves the application on a domain.
5. The **deployment** connects the workload to the application.

For more information about functions, refer to [Functions](/en/documentation/platform/functions/).

---

## Prerequisites

- An Azion account. To create one, refer to [Create an account](/en/documentation/fundamentals/creating-account/).
- A personal token. To create one, refer to [How to manage a personal token](/en/documentation/guides/platform/account-and-billing/personal-tokens/). The CLI also manages tokens with [Azion CLI personal-token](/en/documentation/devtools/cli/resources/personal-token/).
- Node.js and npm. The CLI runs the Azion bundler with `npx` to build the project.

---

## Install the CLI and log in

Install the Azion CLI with the install script:

```bash
curl -fsSL https://cli.azion.app/install.sh | bash
```

If you use Homebrew, install the `azion` formula instead:

```bash
brew install azion
```

Either command puts the `azion` binary on your path. Confirm the installed version:

```bash
azion version
```

The command prints the version:

```text
Azion CLI 4.23.0
```

Save your personal token in the CLI. Replace `[TOKEN VALUE]` with your token:

```bash
azion -t [TOKEN VALUE]
```

The CLI stores the token locally, and later commands use it without the flag. Confirm the account the CLI uses:

```bash
azion whoami
```

The command prints the client ID and email of the account, and the active profile:

```text
 Client ID: 1234u
 Email: you@example.com
 Active Profile: default
```

The CLI is installed and authorized on your account.

---

## Create the project

The `azion init` command creates the project from a preset and a template. Create a project named `my-function`:

```bash
azion init --name my-function
```

Without `--name`, the command asks for the name and suggests a random one. The command then asks five questions. Answer them in this order:

1. **Select the Javascript preset**

   At `? Choose a preset:`, use the arrow keys to select *Javascript*.

2. **Select the Hello World template**

   At `? Choose a template:`, select *Hello World*.

3. **Install the dependencies**

   At `Do you want to install project dependencies?`, enter `Y`.

4. **Skip the local development server**

   At `Do you want to start a local development server?`, enter `n`. `azion dev` starts it later.

5. **Skip the deploy**

   At `Do you want to deploy your project?`, enter `n`. `azion deploy` deploys it later.

The command fetches the template, installs the dependencies, and confirms the project:

```text
? Choose a preset: Javascript
? Choose a template: Hello World

Fetching selected template...

Template successfully fetched
Template successfully configured
🤔 Do you want to install project dependencies? This may be required to generate initial configuration file (Y/n) Y
Installing application dependencies
up to date, audited 1 package in 399ms
found 0 vulnerabilities
…
[Azion] [Build] › ℹ  info      Using preset: javascript
[Azion] [Build] › ✔  success   Build completed successfully with only azion.config
[Azion] [IaC] › ✔  success   Manifest generated successfully at <project-dir>/.edge/manifest.json
🤔 Do you want to start a local development server? (y/N) n
If you want to start a local development server later, run 'azion dev'
Make sure to change to the new working directory before running building or deploying your project
🤔 Do you want to deploy your project? (y/N) n
If you want to deploy your application later, run 'azion deploy'
Make sure to change to the new working directory before running building or deploying your project
Your application my-function was initialized successfully
```

The project is in a new `my-function` directory, with these files:

```text
.
./.edge
./.edge/manifest.json
./.gitignore
./azion
./azion.config.mjs
./azion/azion.json
./index.js
./info.json
./package-lock.json
./package.json
./README.md
./src
./src/function
./src/function/index.js
```

The template writes the function to `src/function/index.js`. It answers every request with `Hello World!`:

```javascript
/**
 * Handle Request
 * This is the input function where you can perform your implementation.
 * @param {Request} request https://developer.mozilla.org/en-US/docs/Web/API/Request
 * @param {*} args function args e.g args.my_secret
 * @returns {Response} https://developer.mozilla.org/en-US/docs/Web/API/Response
 */
async function handleRequest(request, args) {
  const message = `Hello World!`;

  return new Response(message, {
    headers: {
      "content-type": "text/plain;charset=UTF-8",
    },
    status: 200,
  });
}

export { handleRequest };
```

Replace the contents of `src/function/index.js` with the following code. The function then returns the path and method of each request as JSON:

```javascript
/**
 * Handle Request
 * This is the input function where you can perform your implementation.
 * @param {Request} request https://developer.mozilla.org/en-US/docs/Web/API/Request
 * @param {*} args function args e.g args.my_secret
 * @returns {Response} https://developer.mozilla.org/en-US/docs/Web/API/Response
 */
async function handleRequest(request, args) {
  const url = new URL(request.url);
  const body = { message: "Hello from my-function", path: url.pathname, method: request.method };

  return new Response(JSON.stringify(body), {
    headers: {
      "content-type": "application/json;charset=UTF-8",
    },
    status: 200,
  });
}

export { handleRequest };
```

The `my-function` project holds the function code and is ready to run.

---

## Run the function locally

The `dev`, `build`, and `deploy` commands run from inside the project directory. Go to the `my-function` directory:

```bash
cd my-function
```

Start the local development server:

```bash
azion dev
```

The command builds the function and serves it on port 3333:

```text
…
[Azion] [Build] › ℹ  info      Using preset: javascript
[Azion] [Pre-Build] › ℹ  info      Starting pre-build...
[Azion] [Pre-Build] › ℹ  info      Pre-build completed successfully
[Azion] [Build] › ℹ  info      Using preset default entry: index.js
[Azion] [Build] › ⚠  warning   DEPRECATED: Migrate handler to → export default { fetch: (request, env, ctx) => {...} }
[Azion] [Build] › ℹ  info      Starting build...
[Azion] [Build] › ✔  success   Build completed successfully
[Azion] [Post-Build] › ℹ  info      Starting post-build...
[Azion] [Post-Build] › ✔  success   Post-build completed successfully
[Azion] [Server] › ✔  success   Function running on port 0.0.0.0:3333, url: http://localhost:3333
[Azion] [Server] › ℹ  info      Initial scan complete. Ready for changes.
```

The server keeps the terminal busy. In a second terminal, request a path from the server:

```bash
curl -s -i 'http://localhost:3333/hello?x=1'
```

The function answers with a JSON body:

```text
HTTP/1.1 200 OK
content-type: application/json;charset=UTF-8
Date: Thu, 01 Jan 2026 12:00:00 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked

{"message":"Hello from my-function","path":"/hello","method":"GET"}
```

The function runs on your machine and returns the path and method of the request.

---

## Deploy the function

The `azion deploy` command uploads the project, builds it, and creates the function, the application, and the workload. From the `my-function` directory, deploy the project:

```bash
azion deploy
```

The command prints the domain of the workload:

```text
Running deploy command
Uploading source files

Upload completed successfully!
Please visit https://console.azion.com/create/deploy/00000000-0000-0000-0000-000000000001 in case it did not open automatically, to follow up the full deploy process
Your Application was deployed successfully

To visualize your application access the Domain: https://xxxxxxxxxx.map.azionedge.net
Your application is being deployed to all Azion Locations and it might take a few minutes.
```

The deploy records the ID of each object it created in `azion/azion.json`. Later deploys read this file to update the same objects:

```json
{
  "name": "my-function",
  "preset": "javascript",
  …
  "function": [
    {
      "id": 12360,
      "name": "my-function",
      …
      "instance-id": 12363,
      …
    }
  ],
  "application": {
    "id": 1234567893,
    "name": "my-function"
  },
  …
  "rules-engine": {
    …
    "rules": [
      {
        "id": 123461,
        "name": "Execute Function",
        "phase": "request"
      }
    ]
  },
  …
  "workloads": {
    "id": 1234567903,
    "name": "my-function",
    …
    "url": "https://xxxxxxxxxx.map.azionedge.net",
    "deployment_id": [
      {
        "id": 123473,
        "name": "my-function"
      }
    ]
  },
  …
}
```

The first deploy can take several minutes to answer from every location. Until a location has the function, it answers `404` with a page titled `There's nothing here yet`. Wait and retry before you diagnose the deploy.

---

## Check the deployed function

Request the same path from the domain that `azion deploy` printed. Replace `<your-azion-domain>` with that domain:

```bash
curl -s -i 'https://<your-azion-domain>/hello'
```

The function answers with the same JSON body it returned on your machine:

```text
HTTP/2 200 
date: Thu, 01 Jan 2026 12:00:00 GMT
content-type: application/json;charset=UTF-8
x-azion-request-id: 0123456789abcdef0123456789abcdef
x-azion-edge-location: <edge-location>
alt-svc: h3=":443"; ma=86400

{"message":"Hello from my-function","path":"/hello","method":"GET"}
```

The function runs on Azion's distributed infrastructure and answers on the workload domain.

To change the function, edit `src/function/index.js` and run `azion deploy` again from the `my-function` directory. Later deploys take about two minutes to answer from every location.

---

## Next steps

- [How Azion CLI works](/en/documentation/devtools/cli/how-it-works.md): Presets, the build, the azion.json file, profiles, and how the CLI finds your token.
- [Resource commands](/en/documentation/devtools/cli/resources.md): Create, list, describe, update, and delete platform resources from the terminal.
- [Build with a framework](/en/documentation/devtools/cli/guides.md): Deploy a site or an application built with a framework, such as Next.js, Astro, or Vue.
- [Functions](/en/documentation/platform/functions.md): The runtime, limits, and settings of the functions the CLI deploys.
