---
name: azion-migrate-from-akamai-to-azion
description: >-
  Move an Akamai property to Azion: recreate its origins, rules, Cloudlets, EdgeWorkers, and cache, move its data, then switch DNS.
---

# Migrate from Akamai to Azion

An Akamai setup spreads one site across delivery properties, origin behaviors, Cloudlets, EdgeWorkers, EdgeKV data, security policies, DNS zones, traffic steering, storage, and log streams. Moving it means recreating each of these on Azion. Then confirm that the property answers the same way before any production hostname changes.

On Azion, an [application](/en/documentation/platform/applications/) and its rules take over the property: delivery, routing, cache, and headers. [Connectors](/en/documentation/platform/connectors/) reach the origins, and [Functions](/en/documentation/platform/functions/) runs the EdgeWorkers code. [KV Store](/en/documentation/platform/kv-store/), [Object Storage](/en/documentation/platform/object-storage/), and [SQL Database](/en/documentation/platform/sql-database/) hold the data. [Firewall](/en/documentation/platform/firewall/) filters traffic, a [workload](/en/documentation/platform/workloads/) serves the hostname, and [Edge DNS](/en/documentation/platform/edge-dns/) answers for the zone. [Real-Time Metrics](/en/documentation/platform/real-time-metrics/), [Real-Time Events](/en/documentation/platform/real-time-events/), [Data Stream](/en/documentation/platform/data-stream/), and [Edge Pulse](/en/documentation/platform/edge-pulse/) show what happens to each request and each visit.

Each stage of this guide moves one layer, in the order a migration runs: inventory, the property, code and rules, data, security, monitoring, and DNS. DNS and traffic steering come last, once delivery and security answer as expected. When near-zero downtime is not a requirement, migrate in phases with maintenance windows. Writes stop during each step, so the data needs no parallel synchronization.

---

The prerequisites and the procedures on this page switch with the interface you select:

## Prerequisites

- An Azion account. To open one, [sign up in Azion Console](https://console.azion.com/signup). For more information, refer to [Create an account](/en/documentation/fundamentals/creating-account/).
- Access to the Akamai account, with its properties, Cloudlets policies, EdgeWorkers, EdgeKV data, security configurations, and DNS zones.
- Access to the DNS records or the registrar of each hostname you move.
- `curl` and `dig`, to check responses and DNS answers.

**Console**

- Access to Azion Console. To sign in, refer to [Access Azion Console](/en/documentation/guides/platform/account-and-billing/how-to-access-azion-console/).

**CLI**

- The [Azion CLI](/en/documentation/devtools/cli/), installed and authorized with your account. The commands on this page match Azion CLI 4.23.0.

**API**

- A personal token, sent in the `Authorization` header as `Token [TOKEN VALUE]`. To create one, refer to [Manage a personal token](/en/documentation/guides/platform/account-and-billing/personal-tokens/). Every request on this page goes to `https://api.azion.com/v4`.

---

## Inventory the Akamai account

Move one property first, not the most complex one in the portfolio. Pick one that tests the whole path and still moves quickly. A good first property has one or two hostnames, a few origins, cache rules, redirects, and headers. It also has one Cloudlet or EdgeWorker and one log destination. Use it to document the process, then move more complex rules, more EdgeWorkers, data, monitoring, and security in the same order.

A migration can look complete when the first request returns `200`, and still fail later. Cache behavior, redirect logic, origin routing, headers, or security enforcement can differ from the original property. Before you create anything on Azion, list what the property depends on:

- Active properties and property versions.
- Property hostnames, edge hostnames, certificates, and DNS records.
- Origin servers, failover settings, health checks, and shielding patterns.
- Cache keys, TTLs, stale behavior, CP codes, cache tags, and purge workflows.
- Property rules, behaviors, variables, match criteria, and advanced metadata.
- Cloudlets, their policies, match rules, and activation dependencies.
- EdgeWorkers bundles, EdgeKV namespaces, and runtime configuration.
- App & API Protector policies, bot controls, API protections, and Prolexic assumptions.
- Edge DNS zones, DNS Manager records, and Global Traffic Management policies.
- NetStorage content, object storage buckets, and managed databases.
- DataStream streams, TrafficPeak dashboards, mPulse tags, alerts, and external monitoring dependencies.

Each item in the list maps to a stage of this guide. The table in Map each Akamai product to Azion names the destination of each one.

---

## Map each Akamai product to Azion

Every Akamai product in the inventory has a destination on Azion. Find the product in the first column, then move it with the stage that names its destination. A dash (`-`) in the last column means that Azion has no direct equivalent.

| Akamai product                     | What it covers                                                                                            | Destination on Azion                                                                                                                                                                                     |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Account Protector                  | Protection against account abuse and credential attacks                                                   | Bot Manager and Firewall                                                                                                                                                                                 |
| Adaptive Media Delivery            | Large-scale online video delivery                                                                         | Applications, Cache, and Object Storage                                                                                                                                                                  |
| Akamai Functions                   | Distributed serverless execution for application and AI workloads                                         | Functions                                                                                                                                                                                                |
| Akamai Inference Cloud             | Distributed AI inference platform                                                                         | [AI Inference](/en/documentation/platform/ai-inference/)                                                                                                                                                 |
| Akamai TrafficPeak                 | Observability for operations and security visibility                                                      | Real-Time Metrics, Real-Time Events, and Data Stream                                                                                                                                                     |
| API Acceleration                   | API performance and reliability optimization                                                              | [Application Accelerator](/en/documentation/platform/applications/application-accelerator/settings/) and [Cache](/en/documentation/platform/applications/cache/cache-settings/)                          |
| API Gateway                        | API registration, routing, delivery, and protection                                                       | Applications, [Rules Engine](/en/documentation/platform/applications/rules-engine/), Functions, and Firewall                                                                                             |
| API Prioritization Cloudlet        | API traffic prioritization                                                                                | Rules Engine and Application Accelerator                                                                                                                                                                 |
| API Security                       | API discovery, monitoring, and protection workflows                                                       | Firewall, [Web Application Firewall](/en/documentation/platform/firewall/waf/quickstart/), and Applications                                                                                              |
| App & API Protector                | Protection of applications and APIs against vulnerabilities, abuse, and distributed threats               | Firewall, Web Application Firewall, [DDoS Protection](/en/documentation/platform/workloads/#ddos-protection), and [Bot Manager](/en/documentation/platform/firewall/bot-manager/quickstart/)             |
| App Platform                       | Managed containerized application deployment                                                              | [Orchestrator](/en/documentation/platform/orchestrator/), which provisions and manages services on nodes you operate                                                                                     |
| Application Load Balancer Cloudlet | Application load balancing for performance and availability                                               | [Load Balancer](/en/documentation/platform/connectors/load-balancer/quickstart/), a module of Connectors                                                                                                 |
| Audience Segmentation Cloudlet     | Cookie-based segmentation, A/B testing, and session affinity patterns                                     | Rules Engine criteria on cookies and device groups                                                                                                                                                       |
| Bot Manager                        | Bot detection and automated traffic response                                                              | Bot Manager                                                                                                                                                                                              |
| Cloudlets                          | Policy applications for redirects, load balancing, traffic control, phased releases, and request handling | Rules Engine, Functions, Load Balancer, and Firewall                                                                                                                                                     |
| Cloud Firewall                     | Network security controls for cloud workloads                                                             | [Network Shield](/en/documentation/platform/firewall/network-shield/quickstart/) and Firewall                                                                                                            |
| Cloud Wrapper                      | Private caching layer for origin offload and reduced egress                                               | Cache with [Tiered Cache](/en/documentation/platform/applications/cache/tiered-cache/). [Origin Shield](/en/documentation/platform/connectors/origin-shield/origin-ip-acl-and-hmac/) protects the origin |
| Content Protector                  | Protection against content scraping and abusive automated access                                          | Bot Manager, Firewall, and Rules Engine                                                                                                                                                                  |
| Dedicated Delivery                 | High-volume media delivery with origin offload requirements                                               | Applications and Cache, with Tiered Cache                                                                                                                                                                |
| DataStream                         | Data feed to third-party monitoring tools                                                                 | Data Stream                                                                                                                                                                                              |
| DNS Infrastructure                 | DNS services for provider and enterprise environments                                                     | Edge DNS                                                                                                                                                                                                 |
| DNS Manager                        | DNS record management interface                                                                           | Edge DNS                                                                                                                                                                                                 |
| Download Delivery                  | Delivery of large files, software, games, and media assets                                                | Applications, Cache, and Object Storage                                                                                                                                                                  |
| Edge DNS                           | Authoritative DNS                                                                                         | Edge DNS                                                                                                                                                                                                 |
| Edge Redirector Cloudlet           | Centralized redirect management                                                                           | Rules Engine                                                                                                                                                                                             |
| EdgeKV                             | Distributed key-value data for EdgeWorkers                                                                | KV Store                                                                                                                                                                                                 |
| EdgeWorkers                        | JavaScript functions that customize request and response behavior                                         | Functions, run on an application by a [function instance](/en/documentation/platform/applications/functions-instances/)                                                                                  |
| Firewall for AI                    | Protection for LLM and AI-driven applications                                                             | Firewall and AI Inference                                                                                                                                                                                |
| Forward Rewrite Cloudlet           | URL rewrites for clean and semantic URLs                                                                  | Rules Engine and Functions                                                                                                                                                                               |
| Global Traffic Management          | Traffic steering for performance and outage avoidance                                                     | Load Balancer, and weighted records in Edge DNS                                                                                                                                                          |
| Image & Video Manager              | Image and video optimization for devices and network conditions                                           | [Image Processor](/en/documentation/platform/applications/image-processor/quickstart/), for images                                                                                                       |
| Input Validation Cloudlet          | Form and request validation controls                                                                      | Firewall and [Rules Engine for Firewall](/en/documentation/platform/firewall/rules-engine/)                                                                                                              |
| Ion                                | Web performance, reliability, and user experience optimization                                            | Applications, Application Accelerator, and Cache                                                                                                                                                         |
| Managed Databases                  | Managed relational databases                                                                              | SQL Database                                                                                                                                                                                             |
| Media Services Live                | Live video ingest and delivery                                                                            | [Live Ingest](/en/documentation/platform/connectors/live-ingest/ingestion-and-delivery/), delivered by an application                                                                                    |
| mPulse                             | Real-user monitoring and digital experience analytics                                                     | Edge Pulse                                                                                                                                                                                               |
| NetStorage                         | Replicated storage for content delivery                                                                   | Object Storage                                                                                                                                                                                           |
| NodeBalancers                      | Layer 4 and layer 7 load balancing for compute instances                                                  | Load Balancer                                                                                                                                                                                            |
| Object Storage                     | Object storage for data and distribution                                                                  | Object Storage                                                                                                                                                                                           |
| Phased Release Cloudlet            | Gradual release and rollback control                                                                      | Rules Engine and Functions, or weighted addresses in Load Balancer                                                                                                                                       |
| Prolexic Solutions                 | DDoS protection for infrastructure, cloud, hybrid, and on-premises environments                           | DDoS Protection, with custom firewall rules                                                                                                                                                              |
| Request Control Cloudlet           | Access control and request filtering                                                                      | Firewall and Rules Engine for Firewall                                                                                                                                                                   |

Azion holds a SOC 2 Type 2 report and a SOC 3 report, and is a PCI DSS 4.0.1 Level 1 Service Provider. For the attestations, refer to [SOC 2 and SOC 3](/en/documentation/fundamentals/soc/) and [PCI DSS certification](/en/documentation/fundamentals/pci-dss-certification/).

---

## Deploy the property on Azion

An Akamai property becomes an application and a workload on Azion. The application holds the rules, and each origin server becomes a [connector](/en/documentation/platform/connectors/). A rule with *Set Connector* sends requests to it, and a workload serves the application on a domain.

| Aspect            | Akamai                                                           | Azion                                                            |
| ----------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- |
| Delivery resource | Property and property version                                    | Application, served by a workload                                |
| Hostnames         | Property hostnames and edge hostnames                            | **Domains** of a workload                                        |
| Origins           | Origin server behaviors                                          | Connectors                                                       |
| Request logic     | Property rules, behaviors, variables, Cloudlets, and EdgeWorkers | Rules Engine and Functions                                       |
| Cache control     | Property cache behaviors, CP codes, and cache tags               | Cache settings, applied by Rules Engine, and Real-Time Purge     |
| Observability     | TrafficPeak, DataStream, mPulse, and reports                     | Real-Time Metrics, Real-Time Events, Data Stream, and Edge Pulse |

The day-to-day tasks move to the Azion CLI:

| Task        | Akamai workflow                                                  | Azion CLI                                                                        |
| ----------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| Install     | Akamai CLI package and product CLIs                              | `curl -fsSL https://cli.azion.app/install.sh \| bash`, or `brew install azion`   |
| Sign in     | Akamai API credentials and CLI authentication                    | `azion login`                                                                    |
| Run locally | EdgeWorkers sandbox or local application tooling                 | `azion dev`                                                                      |
| Deploy      | Property activation, EdgeWorkers activation, or a CI/CD pipeline | `azion link`, then `azion deploy`, for a project in a repository                 |
| Read logs   | DataStream, reporting, or product dashboards                     | `azion logs http` for requests, and `azion logs cells` for function console logs |
| Purge       | Purge by URL, CP code, cache tag, or API                         | `azion purge --urls`, `--cachekey`, or `--wildcard`                              |

Start with the connector to the origin of the property:

**Console**

To create the connector in Azion Console:

1. **Open the Connectors page**

   Access [Azion Console](https://console.azion.com/) > **Connectors**.

2. **Start a new connector**

3. **Name the connector**

   In **General**, enter `origin-connector` as the **Name**.

4. **Select the HTTP type**

   In **Connector Type**, select the HTTP type.

5. **Enter the origin hostname**

   Under **Address Management**, enter the hostname of the Akamai origin in **Address**, without a protocol or a port.

6. **Send the same hostname in the Host header**

7. **Connect to the origin over HTTPS only**

   In **Transport Protocol Policy**, select the option that uses HTTPS only.

8. **Select Create**

The connector exists in your account. Then create the application, a Request Phase rule with *Set Connector*, and the workload, as the [Applications quickstart](/en/documentation/platform/applications/quickstart/) shows.

**CLI**

To create the connector with the Azion CLI, save its body as `connector.json`, with the hostname of the origin in both places:

```json
{
  "name": "origin-connector",
  "type": "http",
  "attributes": {
    "addresses": [
      { "address": "origin.example.com" }
    ],
    "connection_options": {
      "transport_policy": "force_https",
      "host": "origin.example.com"
    }
  }
}
```

Then create it:

```bash
azion create connector --file connector.json
```

The output carries the ID of the connector. Create the application, the rule, and the workload deployment as the [Applications quickstart](/en/documentation/platform/applications/quickstart/) shows.

**API**

To create the connector, send a `POST` request to the connectors endpoint:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/connectors \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "origin-connector",
  "type": "http",
  "attributes": {
    "addresses": [{ "address": "origin.example.com" }],
    "connection_options": {
      "transport_policy": "force_https",
      "host": "origin.example.com"
    }
  }
}'
```

The response carries `"state": "pending"` and the connector with its `id`. Load Balancer and Origin Shield start off. An application needs only a `name` in `POST /v4/workspace/applications`. Origins and cache settings are not fields of the application. To build the rest of the chain, refer to [Applications quickstart](/en/documentation/platform/applications/quickstart/).

To declare the property in code instead, write the application in an `azion.config.mjs` file. This file holds one cache setting with a TTL of 3,600 seconds, applied to every request. A second rule bypasses the cache for `/api/`:

```javascript
export default {
  applications: [
    {
      name: 'akamai-property-migration',
      active: true,
      applicationAcceleratorEnabled: true,
      cache: [
        {
          name: 'default-cache',
          browser: { maxAgeSeconds: 3600 },
          edge: { maxAgeSeconds: 3600 }
        }
      ],
      rules: {
        request: [
          {
            name: 'Set cache policy',
            active: true,
            criteria: [[{ variable: '${uri}', conditional: 'if', operator: 'starts_with', argument: '/' }]],
            behaviors: [{ type: 'set_cache_policy', attributes: { value: 'default-cache' } }]
          },
          {
            name: 'API routes bypass cache',
            active: true,
            criteria: [[{ variable: '${uri}', conditional: 'if', operator: 'starts_with', argument: '/api/' }]],
            behaviors: [{ type: 'bypass_cache' }]
          }
        ]
      }
    }
  ]
}
```

*Bypass Cache* requires Application Accelerator, which `applicationAcceleratorEnabled` turns on. To send requests to the origin, add a rule whose behavior is `set_connector`, with the connector name or ID in `value`. Run `azion config apply` in the project folder. The command creates each resource and prints its ID. For every key, refer to [azion.config.js](/en/documentation/devtools/cli/azion-config-js/).

When the property fronts a framework project in a GitHub repository, deploy the repository instead. In Azion Console, access **Create**, select the **Import from GitHub** tab, and select **Connect with GitHub**. Then select the repository and the preset: *Next.js*, *Angular*, *Astro*, *Hexo*, *React*, or *Vue*. For the fields, refer to [Import a project from GitHub](/en/documentation/guides/application-development/automation/import-an-existing-project-from-github/).

With the Azion CLI, run `azion link` in the project root, select the preset, then run `azion deploy`. The preset goes in `build.preset` of an `azion.config.js` that imports `defineConfig` from `@aziontech/config`. The preset of a Next.js project is `next`, and the `azion` package of older samples is deprecated. Install that package in the project first, with `npm install -D @aziontech/config`. Without it, the CLI fails with `Failed to load configuration file`. For the commands, refer to [Azion CLI quickstart](/en/documentation/devtools/cli/quickstart/) and [azion deploy](/en/documentation/devtools/cli/deploy/).

The deployment answers on a workload domain that Azion assigns under `map.azionedge.net`. A new workload can take several minutes to serve its first deployment, and answers `404` until then. Send a request to the root path, with that domain in place of `<your-workload-domain>`:

```bash
curl -i https://<your-workload-domain>/
```

The response carries the status, the headers, and the body that the origin returns for `/`. Send the same request to each critical route, such as `/health`. When a response differs from Akamai, compare the active property version with the rules of the application and the connector. For the full chain, refer to [Applications](/en/documentation/platform/applications/), [Main Settings](/en/documentation/platform/applications/main-settings/), and [Connectors](/en/documentation/platform/connectors/).

---

## Move environment variables

EdgeWorkers read configuration from property variables, EdgeKV, or other stores, depending on the implementation. On Azion, variables belong to the account, up to 100 of them, and a function reads them with `Azion.env.get()`. Each variable has a key, a value, and a flag that marks it as a secret.

**Console**

To create the variables in Azion Console, open the **Variables** page of the **Account** menu, and create each variable with its key and its value. Turn a variable that holds a credential into a secret.

**CLI**

To create each variable with the Azion CLI:

```bash
azion create variables --key API_TOKEN --value <your-value> --secret true
```

The CLI answers with the UUID of the new variable, such as `Created variable with UUID 00000000-0000-0000-0000-000000000001`. To list the variables, run `azion list variables`. For the other commands, refer to [variables](/en/documentation/devtools/cli/resources/variables/).

**API**

The Azion CLI and Azion Console create the variables. For the interfaces that create, list, and change a variable, refer to [Environment variables](/en/documentation/platform/functions/environment-variables/).

Then change the code that reads the value:

```javascript diff
-// Before: Akamai configuration access varies by EdgeWorkers implementation
-const apiToken = 'read-from-property-variable-or-secure-store';
 
+// After: Azion Functions
+const apiToken = Azion.env.get('API_TOKEN');
```

A deployed function also reads a variable as `process.env.API_TOKEN`. Under `azion dev`, a function reads the project `.env` file instead of the account variables. If a function reports a variable as not found, confirm that the variable exists on the account. Then confirm that the code reads it with `Azion.env.get()`.

---

## Move EdgeWorkers to Functions

EdgeWorkers run JavaScript that customizes requests and responses. On Azion, this code runs in [Functions](/en/documentation/platform/functions/): request handling, API orchestration, personalization, redirects, authentication, and integrations. A function holds the code, a function instance runs it on an application, and a rule with *Run Function* decides which requests reach it.

| Aspect             | Akamai EdgeWorkers                                              | Azion Functions                                      |
| ------------------ | --------------------------------------------------------------- | ---------------------------------------------------- |
| Deployment unit    | EdgeWorker ID and version                                       | Function, and a function instance on the application |
| Runtime            | Akamai EdgeWorkers JavaScript runtime                           | Azion JavaScript runtime, with standard Web APIs     |
| Entry point        | Event handlers such as `onClientRequest` and `onClientResponse` | `fetch(request, env, ctx)`                           |
| Configuration data | EdgeKV, property variables, and product APIs                    | KV Store, Object Storage, and environment variables  |
| Association        | Property behavior                                               | *Run Function* behavior of a rule                    |

A function has 512 MB of memory per isolate on every plan, and no cold start. On a deployed function, `env` is an empty object, and `ctx` carries `args` and `waitUntil`. An EdgeWorkers event handler becomes a `fetch` handler that returns a response:

```javascript diff
-// Before: Akamai EdgeWorkers style
-export function onClientRequest(request) {
-  const path = request.path;
-  request.setHeader('x-migration-source', 'akamai');
-}
 
+// After: Azion Functions
+export default {
+  async fetch(request, env, ctx) {
+    const url = new URL(request.url);
+    const headers = new Headers(request.headers);
+    headers.set('x-migration-source', 'azion');
+
+    return fetch(`https://origin.example.com${url.pathname}${url.search}`, {
+      method: request.method,
+      headers,
+      body: request.body
+    });
+  }
+};
```

The function forwards the request to the origin with the new header. To add a header with no code, use *Add Request Header* in a rule instead. Map each EdgeWorkers API to its replacement:

| Code area           | Azion replacement                                                                                                            |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| Request parsing     | The standard `Request` and `URL` APIs                                                                                        |
| Response creation   | The standard `Response` API                                                                                                  |
| Headers             | `request.headers` and the headers of the response                                                                            |
| Environment values  | `Azion.env.get()`                                                                                                            |
| Key-value data      | `Azion.KV.open()`, as Move EdgeKV data to KV Store shows                                                                     |
| Objects in a bucket | The `azion:storage` module. Refer to [Object Storage runtime API](/en/documentation/devtools/runtime/api-reference/storage/) |
| External services   | `fetch()`                                                                                                                    |

If EdgeWorkers code fails on Azion, look for Akamai runtime APIs that remain in it. For the runtime APIs, refer to [Web APIs](/en/documentation/devtools/runtime/api-reference/javascript/) and [Functions instances](/en/documentation/platform/applications/functions-instances/).

---

## Recreate redirects and rewrites

Akamai keeps redirects in the Edge Redirector Cloudlet, in property behaviors, or in EdgeWorkers. Azion keeps them in the rules of the application, which you write in Azion Console, the API, or `azion.config.js`. Move simple redirects to rules, and keep Functions for logic that needs code, an external lookup, or signed token validation.

| Aspect           | Akamai                                                        | Azion                                                                                                                           |
| ---------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Simple redirects | Edge Redirector Cloudlet, property behaviors, and EdgeWorkers | *Redirect To (301 Moved Permanently)* in [Rules Engine for Applications](/en/documentation/platform/applications/rules-engine/) |
| URL rewrites     | Forward Rewrite Cloudlet or property rules                    | *Rewrite Request*, or Functions                                                                                                 |
| Captured values  | Match rules                                                   | `%{name[index]}`, such as `%{capture[1]}`, from a *Capture Match Groups* behavior in the same rule                              |

The criteria of a rule select the requests, but they capture nothing. To reuse part of the path in the target, add *Capture Match Groups* before the redirect, in the same rule. *Capture Match Groups* requires [Application Accelerator](/en/documentation/platform/applications/application-accelerator/settings/) on the application. The array is local, so only the rule that captures it can read it.

**Console**

To create the redirect in Azion Console:

1. **Open the application**

   Access [Azion Console](https://console.azion.com/) > **Applications**, then select the application.

2. **Go to the Rules Engine tab**

3. **Select + Rule**

4. **Name the rule**

   Enter a name such as `old-path-redirect`, and select **Request Phase**.

5. **Set the criteria**

   Under **Criteria**, select `${uri}` and the *matches* operator. As the argument, enter `^/old/(.*)$`.

6. **Add the Capture Match Groups behavior**

   Under **Behaviors**, select *Capture Match Groups*. Enter `capture` as the array name, `${uri}` as the **Subject**, and `^/old/(.*)$` as the **Regex**.

7. **Add the redirect**

   Add a second behavior, *Redirect To (301 Moved Permanently)*, with `/new/%{capture[1]}` as the argument.

8. **Select Save**

The rule appears in the list of request rules.

**CLI**

To create the redirect with the Azion CLI, add the rule to the `rules` of the application in `azion.config.js`. Give it the behaviors `capture_match_groups` and `redirect_to_301`, then run `azion deploy`. For the fields of a rule, refer to [azion.config.js](/en/documentation/devtools/cli/azion-config-js/).

**API**

To create the redirect, send a `POST` request to the request rules of the application:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/applications/<application-id>/request_rules \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "old-path-redirect",
  "criteria": [[{ "conditional": "if", "variable": "${uri}", "operator": "matches", "argument": "^/old/(.*)$" }]],
  "behaviors": [
    { "type": "capture_match_groups", "attributes": { "subject": "${uri}", "regex": "^/old/(.*)$", "captured_array": "capture" } },
    { "type": "redirect_to_301", "attributes": { "value": "/new/%{capture[1]}" } }
  ]
}'
```

The response carries `"state": "pending"` and the rule with its `id`.

To check the redirect, request an old path:

```bash
curl -I https://<your-workload-domain>/old/page
```

The response carries `301 Moved Permanently` and a `location` header that ends in `/new/page`. A new rule can take a few minutes to propagate. If the redirect does not fire, test the regular expression and its capture groups against real paths.

---

## Recreate custom headers

Akamai changes headers with the Modify Incoming Request Header and Modify Outgoing Response Header behaviors. Azion adds them with rules in either phase. *Add Request Header* changes the request sent to the origin. The same behavior in a Response Phase rule changes the response sent to the user.

This `azion.config.js` adds two security headers to every response of the application:

```javascript
import { defineConfig } from '@aziontech/config'

export default defineConfig({
  applications: [{
    name: 'my-app',
    rules: {
      response: [{
        name: 'Security Headers',
        active: true,
        criteria: [[{
          variable: '${uri}',
          conditional: 'if',
          operator: 'starts_with',
          argument: '/'
        }]],
        behaviors: [
          { type: 'add_response_header', attributes: { value: 'X-Frame-Options: SAMEORIGIN' } },
          { type: 'add_response_header', attributes: { value: 'X-Content-Type-Options: nosniff' } }
        ]
      }]
    }
  }]
})
```

The value takes the form `Name: value`, and it can carry rule variables, such as `${uri}`. Run `azion deploy`, then check a response:

```bash
curl -I https://<your-workload-domain>/
```

The response carries `x-frame-options: SAMEORIGIN` and `x-content-type-options: nosniff`. If a header is missing, check that a rule in the right phase adds it. For a header computed by code, use a function.

---

## Convert Cloudlet policies

Cloudlets hold policies for redirects, rewrites, segmentation, releases, load balancing, and request control. Azion has no Cloudlets layer. Each policy becomes a rule, a function, a Load Balancer setting, or a firewall rule. Inventory each policy, then convert it with the stage that owns its destination:

| Cloudlet                  | Conversion on Azion                                                                                                                   |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| Edge Redirector           | *Redirect To* behaviors in Rules Engine, as Recreate redirects and rewrites shows                                                     |
| Forward Rewrite           | *Rewrite Request* in Rules Engine, or a function when rebuilding the path needs code                                                  |
| Audience Segmentation     | Rules Engine criteria on `${cookie_name}`, `${device_group}`, `${geoip_country_code}`, or `${uri}`, and *Add Cookie* to set a segment |
| Phased Release            | Rules Engine criteria on a cookie, Functions, or Load Balancer weights on two addresses                                               |
| Application Load Balancer | A connector with Load Balancer, as Balance traffic across origins shows                                                               |
| API Prioritization        | Rules Engine, Application Accelerator, and cache settings                                                                             |
| Input Validation          | Firewall rules, and Functions for Firewall for dynamic or external checks                                                             |
| Request Control           | Firewall rules, as Protect the application with WAF shows                                                                             |

`${device_group}` names a group from the **Device Groups** tab of the application. It requires Application Accelerator, the same as *Add Cookie*. `${cookie_name}` reads one cookie: replace `name` with the cookie name, such as `${cookie_segment}`. For every variable and behavior, refer to [Rules Engine for Applications](/en/documentation/platform/applications/rules-engine/).

---

## Recreate cache settings

On Azion, a [cache setting](/en/documentation/platform/applications/cache/cache-settings/) holds how long a response stays in cache and what makes two requests share one cached copy. A rule with *Set Cache Policy* applies the setting to the requests it matches. The rule selects a setting, and the setting holds the TTL and the cache key.

| Aspect         | Akamai                                         | Azion                                                                                  |
| -------------- | ---------------------------------------------- | -------------------------------------------------------------------------------------- |
| Cache policy   | Property cache behaviors and advanced metadata | Cache settings, applied by *Set Cache Policy*                                          |
| Cache key      | Property behavior and advanced metadata        | **Cache vary by** controls of the cache setting, which require Application Accelerator |
| TTL            | Property cache behaviors                       | **Max Age** of each cache setting, from 0 to 31,536,000 seconds                        |
| Origin offload | Cloud Wrapper and cache hierarchy              | [Tiered Cache](/en/documentation/platform/applications/cache/tiered-cache/)            |
| Purge          | URL, CP code, cache tag, or API                | URL, cache key, and wildcard                                                           |
| Stale content  | Property cache behavior                        | **Stale cache**, which serves an expired copy when revalidation fails                  |

**Max Age** defaults to 60 seconds. A value below 60 requires Application Accelerator, and a cache setting with Tiered Cache on needs at least 3 seconds and *Override cache behavior*. **Stale cache** honors the `stale-while-revalidate` the origin sends, or keeps a 300-second window under *Override cache behavior*. It is on by default in Azion Console and off in the API and the CLI.

**Console**

To create the cache setting in Azion Console:

1. **Open the application**

   Access [Azion Console](https://console.azion.com/) > **Applications**, then select the application.

2. **Go to the Cache Settings tab**

3. **Select + Cache**

4. **Name the cache setting**

   In **Name**, enter `default-cache`.

5. **Keep Override cache behavior selected**

   Under **Cache**, keep *Override cache behavior* selected, so **Max Age** replaces the TTL the origin sends.

6. **Set Max Age**

   In **Max Age**, enter the TTL in seconds. For example: `86400`.

7. **(Optional) Turn on Tiered Cache**

   Turn on **Tiered Cache**, and select the **Tiered Cache Region**.

8. **Select Save**

The new setting appears in the **Cache Settings** list. To apply it, create a Request Phase rule in the **Rules Engine** tab, with the behavior **Set Cache Policy** set to `default-cache`.

**CLI**

The CLI flags cannot set the cache TTL, the cache behavior, or Tiered Cache. Send the full cache setting body from a file with `--file`, as the [Cache quickstart](/en/documentation/platform/applications/cache/quickstart/) shows.

**API**

Cache settings are sub-resources of an application, so each request names the application and, to change one, the setting. To change a setting, send a `PATCH` request:

```bash
curl --request PATCH \
  --url https://api.azion.com/v4/workspace/applications/<application-id>/cache_settings/<cache-setting-id> \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "default-cache",
  "browser_cache": { "behavior": "override", "max_age": 3600 },
  "modules": {
    "cache": {
      "behavior": "override",
      "max_age": 86400,
      "tiered_cache": { "enabled": true, "topology": "nearest-region" }
    }
  }
}'
```

To create a setting, send the same body in a `POST` request to `/v4/workspace/applications/<application-id>/cache_settings`. Then apply it with a request rule whose behavior is `{ "type": "set_cache_policy", "attributes": { "value": <cache-setting-id> } }`.

To vary the cache by query string, cookie, or device, use **Cache vary by Query String**, **Cache vary by Cookies**, and **Cache vary by Devices**. They require Application Accelerator on the application. For the steps, refer to [Configure Advanced Cache Key](/en/documentation/guides/application-performance/cache-and-purge/advanced-cache-key/) and [Cache variation](/en/documentation/platform/applications/application-accelerator/cache-variation/).

To purge cached content, send a `POST` request to the purge endpoint of its type:

```bash
# Purge by URL
curl --request POST \
  --url https://api.azion.com/v4/workspace/purge/url \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "items": ["https://www.example.com/images/logo.png"],
  "layer": "cache"
}'

# Purge by wildcard
curl --request POST \
  --url https://api.azion.com/v4/workspace/purge/wildcard \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "items": ["https://www.example.com/images/*"],
  "layer": "cache"
}'
```

A URL purge takes up to 50 items, and a wildcard purge takes one expression. Only a cache key purge, at `/v4/workspace/purge/cachekey`, reaches Tiered Cache with `"layer": "tiered_cache"`. With the Azion CLI, `azion purge --urls` prints `Purge carried out successfully`. Validate the purge workflow before the cutover. For the purge types, refer to [Real-Time Purge](/en/documentation/platform/applications/cache/real-time-purge/).

If fewer responses come from cache after the move, review the cache settings, their **Cache vary by** controls, and Tiered Cache. Azion purges by URL, cache key, or wildcard, so map each purge by CP code or cache tag to one of these.

---

## Balance traffic across origins

On Azion, [Load Balancer](/en/documentation/platform/connectors/load-balancer/balancing-methods/) is a module of a connector, not a separate resource. One connector of type `http` holds every origin as an address, up to 15 addresses with Load Balancer on, and one address without it. A rule with *Set Connector* sends the requests of the application to the connector.

| Aspect            | Akamai                                                                           | Azion Load Balancer                                                                                                 |
| ----------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| Origin resource   | Origin server behavior                                                           | Addresses of one connector                                                                                          |
| Load balancing    | Application Load Balancer Cloudlet, NodeBalancers, and Global Traffic Management | *Round Robin*, *Least Connections*, and *IP Hash*, which are `round_robin`, `least_conn`, and `ip_hash` in the API  |
| Health checks     | Product-specific health checks                                                   | None. Failover is passive: **Max Retries** and the timeouts handle a failed connection                              |
| Failover          | Property rules, Global Traffic Management, or product configuration              | Several *Primary* addresses with weights, and *Backup* addresses that receive traffic only when every primary fails |
| Origin protection | Cloud Wrapper and the caching hierarchy                                          | Tiered Cache offloads the origin. Origin Shield restricts it to Azion addresses and signs requests with HMAC        |

No method steers by location, and there is no cookie affinity. *IP Hash* maps each client IP address to one address. Each address has a **Weight** from 1 to 100, which sets its share of the traffic. *IP Hash* refuses *Backup* addresses, with `28005` in the API.

**Max Retries** takes 0 to 20, **Connection Timeout** 1 to 300 seconds, and **Read/Write Timeout** 1 to 600 seconds. These fields exist only with Load Balancer on. When you turn it on in Azion Console, the form fills in *Round Robin*, `3`, `30`, and `60`. The API defaults are `0`, `60`, and `120`.

**Console**

To turn on Load Balancer in Azion Console:

1. **Open the Connectors page**

   Access [Azion Console](https://console.azion.com/) > **Connectors**.

2. **Open the connector of the origin**

3. **Turn on Load Balancer**

   In **Modules**, turn on **Load Balancer**.

4. **Select the balancing method**

   In **Load Balancer Configuration**, set **Method** to *Round Robin*, *Least Connections*, or *IP Hash*.

5. **Set the first address**

   Under **Address Management**, on the existing address, set **Server Role** and **Weight**.

6. **Select Add Address**

7. **Enter the next origin**

   In the new **Address**, enter the host of the origin, without a protocol or a port. Then set its **Server Role** and **Weight**.

8. **Select Save**

The Console shows `Connector has been updated`. The connector has Load Balancer on and one address for each origin.

**CLI**

The update command needs the full connector body. Put it in a JSON file and send it with `--file`, as the [Load Balancer quickstart](/en/documentation/platform/connectors/load-balancer/quickstart/) shows.

**API**

To turn on Load Balancer, send a `PATCH` request to the connector. Each address carries `server_role` and `weight`, and the method sits in `attributes.modules.load_balancer.config`:

```bash
curl --request PATCH \
  --url https://api.azion.com/v4/workspace/connectors/<connector-id> \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "attributes": {
    "addresses": [
      { "address": "origin1.example.com", "active": true, "modules": { "load_balancer": { "server_role": "primary", "weight": 3 } } },
      { "address": "origin2.example.com", "active": true, "modules": { "load_balancer": { "server_role": "primary", "weight": 1 } } }
    ],
    "modules": {
      "load_balancer": {
        "enabled": true,
        "config": { "method": "round_robin", "max_retries": 3, "connection_timeout": 10, "read_write_timeout": 30 }
      }
    }
  }
}'
```

The response carries `"state": "pending"`. Two addresses with Load Balancer off are refused with `28004`, and `"enabled": true` with an empty `config` is refused with `28014`.

For the connector fields, refer to [Connector settings](/en/documentation/platform/connectors/settings/). For Origin Shield, refer to [Origin IP ACL and HMAC](/en/documentation/platform/connectors/origin-shield/origin-ip-acl-and-hmac/).

---

## Serve optimized images

[Image Processor](/en/documentation/platform/applications/image-processor/quickstart/) replaces the image side of Image & Video Manager. It resizes, crops, converts, and filters images on request. It stores nothing: it reads the source image from the origin of the application, which can be an Object Storage bucket.

Image Processor works in two steps: turn on the module on the application, then create a rule with the *Optimize Images* behavior. A request that no such rule matches is delivered unprocessed.

**Console**

To turn on Image Processor in Azion Console:

1. **Open the application**

   Access [Azion Console](https://console.azion.com/) > **Applications**, then select the application.

2. **Turn on Image Processor**

   In the **Main Settings** tab, under **Modules**, turn on **Image Processor**.

3. **Select Save**

4. **Add the Optimize Images rule**

   In the **Rules Engine** tab, create a Request Phase rule with `${uri}` *matches* `\.(jpg|jpeg|gif|bmp|png|ico|webp|avif)` and the *Optimize Images* behavior.

Image requests that match the rule are now processed.

**CLI**

To turn on Image Processor with the Azion CLI, follow the CLI panel of the [Image Processor quickstart](/en/documentation/platform/applications/image-processor/quickstart/).

**API**

To turn on the module, send a `PATCH` request to the application with `{ "modules": { "image_processor": { "enabled": true } } }`. Then create a request rule with the `optimize_images` behavior, as the [Image Processor quickstart](/en/documentation/platform/applications/image-processor/quickstart/) shows.

Image Processor reads the transformation from the `ims` query parameter:

```text
# Akamai: image transformation patterns vary by implementation
https://www.example.com/image.jpg?width=400&quality=85

# Azion
https://www.example.com/image.jpg?ims=400x/filters:quality(85)
```

| Syntax                                | Result                                                             | Example                                   |
| ------------------------------------- | ------------------------------------------------------------------ | ----------------------------------------- |
| `?ims=WxH`                            | Resizes to the width and height, cropping to fit when both are set | `?ims=400x300`                            |
| `?ims=Wx`                             | Resizes to the width, with the height in proportion                | `?ims=400x`                               |
| `?ims=xH`                             | Resizes to the height, with the width in proportion                | `?ims=x300`                               |
| `?ims=fit-in/WxH`                     | Fits the image inside the dimensions, never enlarging it           | `?ims=fit-in/400x300`                     |
| `?ims=fit-in/WxH/filters:fill(Color)` | Fits the image and fills the rest of the canvas with a color       | `?ims=fit-in/400x300/filters:fill(white)` |

Image Processor converts to WebP when the `Accept` header of the client allows it. AVIF needs `?ims=filters:format(avif)` and a client that accepts `image/avif`. For every parameter, refer to [URL parameters](/en/documentation/platform/applications/image-processor/url-parameters/). For the setup, refer to [Configure Image Processor on an application](/en/documentation/guides/application-performance/delivery-optimization/process-images/).

---

## Deliver media, downloads, and live streams

Adaptive Media Delivery, Download Delivery, Dedicated Delivery, and Media Services Live carry bandwidth-heavy traffic. Move each one by its traffic model: cacheable media, video on demand, large files, or live streams.

| Akamai product           | Azion path                                                   |
| ------------------------ | ------------------------------------------------------------ |
| Adaptive Media Delivery  | Applications and Cache, with the media in Object Storage     |
| Download Delivery        | Applications and Cache, with the files in Object Storage     |
| Dedicated Delivery       | Applications and Cache, with Tiered Cache for origin offload |
| Media Services Live      | Live Ingest, delivered by an application                     |
| Cloud Wrapper, for media | Tiered Cache                                                 |

[Live Ingest](/en/documentation/platform/connectors/live-ingest/ingestion-and-delivery/) takes the live stream from your encoder into a connector of type `live_ingest`. The encoder pushes over RTMP, with username and password authentication. Live Ingest converts the stream to HLS, and an application delivers it to viewers through that connector.

The connector carries one attribute, `region`: `us-east-1`, `us-east-2`, `br-east-1`, `br-east-2`, or `br-east-3`. Azion provides a primary and a backup ingestion endpoint. Put them in different regions, so one regional failure cannot stop the broadcast. The *Enforce HLS cache* behavior applies the cache policy Azion defines for live HLS, and requires Live Ingest.

For the encoder settings and the event checklist, refer to [Connectors best practices](/en/documentation/platform/connectors/best-practices/#live-ingest). For the HLS cache rules, refer to [Enforce HLS cache for live streaming](/en/documentation/guides/media-and-streaming/streaming/enforce-hls-cache/).

---

## Route APIs and call AI models

API Gateway and API Acceleration patterns move to an application. Rules route the paths, Functions holds the API logic, and Firewall protects the routes. Application Accelerator and Cache speed up the responses.

| Aspect           | Akamai                                              | Azion                                                   |
| ---------------- | --------------------------------------------------- | ------------------------------------------------------- |
| API routing      | API Gateway and property rules                      | Applications and Rules Engine                           |
| API logic        | EdgeWorkers, Akamai Functions, or upstream services | Functions                                               |
| API protection   | App & API Protector and API Security                | Firewall, Web Application Firewall, and Bot Manager     |
| API acceleration | API Acceleration                                    | Application Accelerator and Cache                       |
| AI execution     | Akamai Inference Cloud or external providers        | AI Inference, or external AI APIs called from Functions |

This function sends `/api/` requests to an API origin, with a token from an environment variable. Every other request goes to the main origin, with its headers unchanged:

```javascript
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    const headers = new Headers(request.headers);
    let origin = 'https://origin.example.com';

    if (url.pathname.startsWith('/api/')) {
      origin = 'https://api-origin.example.com';
      headers.set('Authorization', 'Bearer ' + Azion.env.get('API_TOKEN'));
    }

    return fetch(origin + url.pathname + url.search, {
      method: request.method,
      headers,
      body: request.body
    });
  }
};
```

[AI Inference](/en/documentation/platform/ai-inference/) runs a catalog of open-source [models](/en/documentation/platform/ai-inference/models/). A function calls a model by its ID with `Azion.AI.run()`, and needs no credential:

```javascript
const modelResponse = await Azion.AI.run("Qwen/Qwen3-30B-A3B-Instruct-2507-FP8", {
  "stream": false,
  "messages": [
    { "role": "system", "content": "You are a helpful assistant." },
    { "role": "user", "content": "Name three European capitals." }
  ]
})
const answer = modelResponse?.choices?.[0]?.message?.content
```

Under `azion dev`, `Azion.AI` is `undefined`, so test the call on a deployed function. For the request fields, refer to [Model invocation](/en/documentation/platform/ai-inference/model-invocation/).

---

## Move EdgeKV data to KV Store

[KV Store](/en/documentation/platform/kv-store/) holds configuration, feature flags, session metadata, and lightweight state, the same uses EdgeKV serves.

| Aspect          | Akamai EdgeKV                                 | Azion KV Store                                                  |
| --------------- | --------------------------------------------- | --------------------------------------------------------------- |
| Data model      | Namespaces, groups, and items                 | Namespaces of keys and values                                   |
| Access          | From EdgeWorkers                              | From Functions, through `Azion.KV.open()`                       |
| Migration focus | Export, transform, import, and validate reads | Create the namespace, import the keys, and update the functions |

EdgeKV addresses an item by namespace, group, and item. KV Store has no groups, so fold the group into the key, such as `features:checkout`:

```javascript diff
-// Before: Akamai EdgeKV-style pseudocode
-const value = await edgeKv.getText({ namespace: 'config', group: 'features', item: 'checkout' });
 
+// After: Azion KV Store
+const kv = await Azion.KV.open('config');
+const value = await kv.get('features:checkout');
+await kv.put('features:checkout', 'enabled');
```

`get()` returns text by default, and `null` for a missing key. `Azion.KV.open()` is the only entry point. The namespace must exist first, or `open()` throws `NotFound`.

**Console**

Azion Console has no KV Store screen. Create the namespace through the API, on the **API** tab. For the fields and the errors, refer to [Namespaces](/en/documentation/platform/kv-store/namespaces/).

**CLI**

Create the namespace through the API, on the **API** tab.

**API**

To create the namespace, send a `POST` request to the namespaces endpoint:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/kv/namespaces \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "akamai-migration-kv"
}'
```

The response carries `201` and the namespace.

A namespace name takes 3 to 63 characters, is case-sensitive, and is permanent: a namespace cannot be renamed or deleted. KV Store has no bulk import, and no API, CLI command, or Console screen writes keys. To move the data:

1. Export the namespaces, groups, items, metadata, and expiration rules from Akamai.
2. Decide how each group and item maps to a key, and keep the existing prefixes and naming conventions where possible.
3. Write the keys from a deployed function with `kv.put()`.

The function writes a key at most once per second. A value takes up to 25 MB, a key up to 512 bytes, and the metadata up to 1,024 bytes. Map each expiration to the `expiration` option, in Unix seconds, or to `expirationTtl`, in seconds with a minimum of 60. A write becomes visible everywhere within 60 seconds.

Before production traffic moves, document what the code does with a missing key, and check value encoding, JSON serialization, and binary data. Test the read and write paths. If data is missing, export the keys again, and check the namespace name and the encoding. For the client, refer to [KV Store runtime API](/en/documentation/devtools/runtime/api-reference/kv-store/) and [Manage key-value data from a function](/en/documentation/guides/application-development/data/manage-with-functions/).

---

## Move NetStorage to Object Storage

[Object Storage](/en/documentation/platform/object-storage/) holds images, documents, static assets, media, downloads, uploads, and generated files. It speaks the S3 protocol, so S3 tools and SDKs reach it with a new endpoint, a region, and a key pair.

| Aspect            | Akamai NetStorage or Object Storage                                  | Azion Object Storage                                       |
| ----------------- | -------------------------------------------------------------------- | ---------------------------------------------------------- |
| Protocol          | NetStorage APIs, or S3-compatible workflows depending on the product | S3                                                         |
| Endpoint          | Akamai storage endpoint                                              | `s3.us-east-005.azionstorage.net`, in region `us-east-005` |
| Object management | Product-specific tools or S3-compatible tools                        | S3-compatible tools, the API, the CLI, and the runtime API |
| Delivery to users | Delivery property                                                    | An application, with a connector to the bucket             |

The key pair comes from an Object Storage credential. Create it in Azion Console or with a `POST` request to `https://api.azion.com/v4/workspace/storage/credentials`. The `secret_key` comes back only in the create response. To migrate, the credential needs at least `listBuckets`, `listFiles`, and `writeFiles`, plus `listAllBucketNames` to list the buckets.

A Node.js migration script reaches Object Storage with the AWS SDK:

```javascript
import { S3Client } from '@aws-sdk/client-s3';

const client = new S3Client({
  region: 'us-east-005',
  endpoint: 'https://s3.us-east-005.azionstorage.net',
  credentials: {
    accessKeyId: process.env.AZION_ACCESS_KEY,
    secretAccessKey: process.env.AZION_SECRET_KEY
  }
});
```

When the source speaks S3, copy the objects with s3cmd, rclone, or the AWS CLI. For NetStorage-specific workflows, export the content to a local folder or an intermediate bucket first. Create the destination bucket in Azion Console, the API, or the CLI: `s3cmd mb` and `s3cmd rb` are refused with `403 AccessDenied`. A bucket name takes 6 to 63 characters, is unique across all accounts, and cannot start with `azion`.

| Task                 | s3cmd command                                                                                 |
| -------------------- | --------------------------------------------------------------------------------------------- |
| List buckets         | `s3cmd ls`, which needs `listAllBucketNames` on the credential                                |
| Upload an object     | `s3cmd put file.png s3://my-bucket/`                                                          |
| Download an object   | `s3cmd get s3://my-bucket/file.png`                                                           |
| Copy between buckets | `s3cmd sync s3://source-bucket/ s3://dest-bucket/`, between buckets of the same provider only |

To upload an exported folder with [s3cmd](https://s3tools.org/s3cmd), configure it for Azion with `s3cmd --configure -c ~/.s3cfg-azion`. Enter the key pair, `us-east-005` as **Default Region**, and `s3.us-east-005.azionstorage.net` as **S3 Endpoint**. Then sync the folder:

```bash
s3cmd -c ~/.s3cfg-azion sync ./export/ s3://azion-bucket/
```

The objects are in the Azion bucket. To check, run `s3cmd -c ~/.s3cfg-azion ls s3://azion-bucket/`. If access is denied, check the key pair and the endpoint `s3.us-east-005.azionstorage.net`.

Azion Console refuses a single upload over 300 MB, and the API and S3 tools are not bound by that limit. Use the S3 endpoint to manage objects only. Deliver them to users through a connector and an application, so cache, security, and the production domain apply. For the steps, refer to [Use S3-compatible tools](/en/documentation/guides/application-development/data/use-s3-compatible-tools-with-object-storage/), [Create and modify a bucket](/en/documentation/guides/application-development/data/create-and-modify-bucket/), [Upload and download objects](/en/documentation/guides/application-development/data/upload-and-download-objects-from-bucket/), and [Use a bucket as origin](/en/documentation/guides/application-development/data/use-bucket-as-origin/).

---

## Move managed databases to SQL Database

[SQL Database](/en/documentation/platform/sql-database/) uses the SQLite dialect and is fully ACID-compliant. One main instance takes every write, and read replicas answer reads. SQL Database is in Preview on every plan.

| Aspect             | Akamai Managed Databases                                 | Azion SQL Database                                                 |
| ------------------ | -------------------------------------------------------- | ------------------------------------------------------------------ |
| Data model         | MySQL or PostgreSQL, depending on the source service     | SQLite dialect                                                     |
| Application access | A connection string from the application or service      | A read-only connection from a function, and writes through the API |
| Migration focus    | Export the schema, data, users, and connection settings  | Create the database, import the data, and validate the queries     |
| Validation         | Backups, replicas, connection limits, and query behavior | Query behavior and the functions that read the data                |

To move a database:

1. Export the schema, data, indexes, users, and extension requirements from the source database.
2. [Create the database](/en/documentation/guides/application-development/data/manage-sql-database/) on Azion.
3. Import the data, and validate the row counts.
4. Update the connection settings of the application, or the functions that read the data.
5. Run read and write tests at the application level before the cutover.

The EdgeSQL Shell reads one table at a time from a live MySQL or PostgreSQL server, with `.import mysql` or `.import postgres`. The shell does not start on a clean install, so check [EdgeSQL Shell](/en/documentation/platform/sql-database/edgesql-shell/) before you rely on it. You can also send SQL statements in the `statements` array of a `POST` request to `https://api.azion.com/v4/workspace/sql/databases/<database-id>/query`.

A function reads the database with `Database.open()` from the `Azion.Sql` global. An `insert` or `delete` through that connection fails with `attempt to write a readonly database`. For the import paths, refer to [Import data into SQL Database](/en/documentation/guides/application-development/data/import-data-sql-database/). For the runtime API, refer to [SQL Database runtime API](/en/documentation/devtools/runtime/api-reference/sql-database/).

---

## Protect the application with WAF

[Web Application Firewall](/en/documentation/platform/firewall/waf/quickstart/) takes over the managed protections of App & API Protector. It scores requests against eight threat families. A WAF rule set holds a sensitivity for each family, and a firewall rule applies it with *Set WAF*.

| Aspect             | Akamai App & API Protector                          | Azion WAF and Firewall                                                                           |
| ------------------ | --------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Managed protection | Managed rules and protections                       | One managed ruleset, scored per threat family                                                    |
| Custom logic       | Match targets, custom rules, and policy settings    | [Rules Engine for Firewall](/en/documentation/platform/firewall/rules-engine/)                   |
| Actions            | Alert, deny, challenge, or product-specific actions | *Deny*, *Drop*, *Set Custom Response*, *Set Rate Limit*, *Set WAF*, and *Run Function*           |
| Tuning             | Policy tuning and exceptions                        | *Logging* and *Blocking* modes, a sensitivity per family, WAF exceptions, and the **Tuning** tab |
| Association        | Security policy and protected hostname              | A firewall, bound to the workload                                                                |

`mode` is required on every *Set WAF* behavior, and it has no default. Start in *Logging*, and compare false positives, the top triggered rules, and the exceptions the application needs. Then switch to *Blocking*. In *Blocking* mode, a request the rule set blocks receives `400`.

**Console**

To set up WAF in Azion Console:

1. **Create the rule set**

   Access [Azion Console](https://console.azion.com/) > **Edge Libraries** > **WAF Rules**, and create a rule set. Set the sensitivity of each family in **Threat Type Configuration**.

2. **Open the firewall**

   Go to **Secure** > **Firewalls**, and select or create the firewall.

3. **Turn on Web Application Firewall**

   In the **Main Settings** tab, under **Modules**, turn on **Web Application Firewall**, and select **Save**.

4. **Apply the rule set**

   In the **Rules Engine** tab, create a rule with the *Set WAF* behavior. In **Select a WAF**, select the rule set. In **Select a WAF mode**, select *Logging*.

5. **Bind the firewall to the workload**

   In the workload, under **Deployment Settings**, select the firewall in **Firewall**.

The firewall applies the rule set to the requests of the workload.

**CLI**

To bind a firewall with the Azion CLI, pass `--firewall-id` to the workload deployment. For the rule set and the rule, follow the [WAF quickstart](/en/documentation/platform/firewall/waf/quickstart/).

**API**

To create the rule set, send a `POST` request to the WAF endpoint:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/wafs \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "active": true,
  "name": "Akamai Migration WAF",
  "product_version": "1.0",
  "engine_settings": {
    "engine_version": "2021-Q3",
    "type": "score",
    "attributes": {
      "rulesets": [1],
      "thresholds": [
        { "threat": "sql_injection", "sensitivity": "medium" }
      ]
    }
  }
}'
```

`rulesets` accepts only `[1]`. Then apply the rule set with a firewall rule whose behavior is `{ "type": "set_waf", "attributes": { "waf_id": <waf-rule-set-id>, "mode": "logging" } }`.

The policy rules of App & API Protector, the Request Control Cloudlet, and the Input Validation Cloudlet become firewall rules. Firewall variables differ from application variables: the path is `${request_uri}`. An address range goes in a [Network List](/en/documentation/platform/firewall/network-shield/network-lists/), matched with `${network}`:

```text
# Akamai intent
Block requests to /admin unless the client IP is in an approved network.

# Azion criteria
${request_uri}  starts with     /admin
and
${network}      is not in list  <network-list-id>   (a Network List that holds 10.0.0.0/8)

Behavior: Deny (403 Forbidden)
```

The `${network}` criterion requires Network Shield on the firewall. To protect a route without an address check, send the rule to the request rules of the firewall:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/firewalls/<firewall-id>/request_rules \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Protect API Admin Routes",
  "active": true,
  "criteria": [[{ "variable": "${request_uri}", "conditional": "if", "operator": "starts_with", "argument": "/api/admin" }]],
  "behaviors": [{ "type": "deny" }]
}'
```

The response carries `"state": "pending"` and the rule. A matching request receives `403` with the Forbidden error page. *Deny* takes no attributes. For checks that need code or an external service, run a function on the firewall. For details, refer to [Functions for Firewall](/en/documentation/platform/firewall/functions/) and [WAF rule sets](/en/documentation/platform/firewall/waf/rules-set/).

---

## Rely on DDoS Protection

[DDoS Protection](/en/documentation/platform/workloads/#ddos-protection) takes over the role of Prolexic for the traffic Azion serves. It is on for every workload, with nothing to create and nothing to configure. It mitigates volumetric, protocol, and application-layer attacks on layers 3, 4, 6, and 7. Examples are UDP and ICMP floods, SYN floods, packet fragmentation, HTTP floods, and slowloris.

| Aspect        | Akamai Prolexic and DDoS products          | Azion DDoS Protection                                |
| ------------- | ------------------------------------------ | ---------------------------------------------------- |
| Activation    | Product and traffic steering configuration | Automatic, and it cannot be turned off               |
| Layers        | Network and application layers             | 3, 4, 6, and 7                                       |
| Customization | Prolexic and security policy controls      | Custom firewall rules                                |
| Visibility    | Akamai security dashboards and logs        | Real-Time Metrics, Real-Time Events, and Data Stream |

A firewall shows the **DDoS Protection Unmetered** switch in **Main Settings** > **Modules**, always on. In the API, `modules.ddos_protection` is read-only. DDoS Protection has no thresholds, no per-rule switches, and no alerts. Layers 3 and 4 are unmetered, and layer 7 mitigation can generate chargeable traffic.

To move from Prolexic:

1. Document the current Prolexic assumptions, protected prefixes, routing model, support processes, and escalation paths.
2. Confirm the workload, the firewall, and the Network Shield configuration on Azion.
3. Recreate the application-layer controls as rules of the firewall bound to the workload.
4. Confirm that Real-Time Metrics, Real-Time Events, and Data Stream show the traffic.
5. Have the rollback and escalation procedures on hand for the cutover window.

The Security Response Team is an add-on to Enterprise and Mission-Critical support. [Network Shield](/en/documentation/platform/firewall/network-shield/quickstart/) is a different module of the firewall. It matches the client address against a Network List of IP addresses, CIDR ranges, ASNs, or countries, through `${network}`. For the attack types, refer to [Attack mitigation](/en/documentation/platform/workloads/ddos-protection/ddos-mitigation/).

---

## Recreate bot management

[Bot Manager](/en/documentation/platform/firewall/bot-manager/quickstart/) takes over from Akamai Bot Manager, Account Protector, and Content Protector. It scores each request and acts on the score. Bot Manager Lite is the Marketplace function included on every plan, and the full Bot Manager is available on Enterprise.

| Aspect             | Akamai                                              | Azion Bot Manager                                                                                                    |
| ------------------ | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| Detection          | Bot, account, and content protection signals        | Static rules, a dynamic behavioral method in the full Bot Manager, device fingerprints, and reputation Network Lists |
| Actions            | Allow, deny, challenge, or product-specific actions | `allow`, `custom_html`, `deny`, `drop`, `hold_connection`, `random_delay`, and `redirect`                            |
| Rule integration   | Security policy controls                            | A function instance, run by a firewall rule                                                                          |
| Lightweight option | Product-specific configuration                      | Bot Manager Lite, from Marketplace                                                                                   |

Bot Manager Lite scores a request with 26 static rules, against a `threshold` that defaults to 30, and takes the `deny` action by default. It can also check the client against reputation Network Lists.

To set up Bot Manager Lite in Azion Console:

1. **Install the integration**

   Access [Azion Console](https://console.azion.com/) > **Marketplace**, search for **Bot Manager Lite**, and select **Install**. The installation takes effect at once.

2. **Open the firewall**

   Go to **Firewalls**, and select a firewall with the **Functions** module on.

3. **Create the function instance**

   In the **Functions Instances** tab, create an instance of Bot Manager Lite. In its JSON arguments, set `threshold` and `action`.

4. **Run the function**

   In the **Rules Engine** tab, create a rule with the *Run Function* behavior and the instance.

5. **Bind the firewall to the workload**

The firewall scores the requests of the workload. For every argument, refer to [Bot Manager Lite](/en/documentation/platform/firewall/bot-manager/bot-manager-lite/) and [Install Bot Manager Lite](/en/documentation/guides/application-development/integrations/bot-manager-lite/). To deploy it from a template instead, refer to [Add Bot Manager Lite to a Firewall](/en/documentation/guides/application-development/integrations/bot-manager-lite-integration-kit/).

To block a client by its user agent, add a firewall rule:

```text
Criteria: ${header_user_agent} matches BadBot
Behavior: Deny (403 Forbidden)
```

`${header_user_agent}` requires the WAF module on the firewall and supports only *matches* and *does not match*. The firewall has no allow behavior. To exempt a client, such as a search crawler, add a *does not match* criterion to the deny rule, or order the rules. A client can send any user agent, so verify a good bot another way. To check the rule:

```bash
curl -A "BadBot/1.0" https://<your-domain>/
curl -A "Mozilla/5.0" https://<your-domain>/
```

The first response is `403`, with the Forbidden error page. The second receives the normal response.

---

## Recreate rate limits

Azion limits request rates in two ways, and each fits a different need. Use the native *Set Rate Limit* behavior of a firewall rule to cap the requests per second or per minute. It counts per client IP address or across all clients. Use the [Upstash Rate Limiting](/en/documentation/guides/application-development/integrations/upstash-rate-limiting-integration/) integration, a rate limit with penalty run as a firewall function, for custom keys, custom windows, or a penalty period.

| Capability      | Native *Set Rate Limit*                   | Upstash Rate Limiting function                                                       |
| --------------- | ----------------------------------------- | ------------------------------------------------------------------------------------ |
| Count key       | Client IP address or global               | Any combination of request metadata, headers, and the hostname                       |
| Window          | Per second or per minute                  | Any interval in seconds or minutes, with different limits for different times of day |
| Algorithm       | Leaky bucket, counted in each data center | Fixed window, sliding window, or token bucket, counted globally                      |
| Response        | `429`, with no rate-limit header          | `429` at the limit, and `403` during a penalty                                       |
| Log-only action | None                                      | None                                                                                 |
| Requirements    | None                                      | An Upstash account and Global Database                                               |

### Use the native rate limit

A *Set Rate Limit* behavior counts the requests its rule matches. The criteria of the rule scope the limit, such as the path with `${request_uri}`. **Rate Limit Type** is *Req/s* or *Req/min*, and **Limit By** is *Client IP address* or *Global*. **Average Rate Limit** takes at least 1, and **Maximum Burst Size** takes at least 1 and applies to *Req/s* only. No behavior can follow *Set Rate Limit* in a rule. A rule whose criteria join several paths with `or` shares one count across all of them.

**Console**

To create the rate limit in Azion Console:

1. **Open the firewall**

   Access [Azion Console](https://console.azion.com/) > **Secure** > **Firewalls**, and select the firewall.

2. **Go to the Rules Engine tab**

3. **Select + Rule**

4. **Set the criteria**

   Under **Criteria**, select `${request_uri}`, the *starts with* operator, and `/api/` as the argument.

5. **Add the Set Rate Limit behavior**

   Under **Behaviors**, select *Set Rate Limit*. Set **Rate Limit Type** to *Req/s*, **Limit By** to *Client IP address*, **Average Rate Limit** to `10`, and **Maximum Burst Size** to `10`.

6. **Select Save**

The rule appears in the list of firewall rules.

**CLI**

To create the rule with the Azion CLI, save the rule body of the API panel in a file. Then pass the file with `--file` to the firewall rule command. For the commands, refer to [Firewall quickstart](/en/documentation/platform/firewall/quickstart/).

**API**

To create the rate limit, send a `POST` request to the request rules of the firewall:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/firewalls/<firewall-id>/request_rules \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "api rate limit",
  "active": true,
  "criteria": [
    [{ "variable": "${request_uri}", "conditional": "if", "operator": "starts_with", "argument": "/api/" }]
  ],
  "behaviors": [
    { "type": "set_rate_limit", "attributes": { "type": "second", "limit_by": "client_ip", "average_rate_limit": 10, "maximum_burst_size": 10 } }
  ]
}'
```

The response carries `"state": "pending"` and the rule.

A request beyond the rate and the burst receives `429`, with the error page titled Too Many Requests. For how the rate and the burst admit requests, refer to [Set Rate Limit](/en/documentation/platform/firewall/rules-engine/#set-rate-limit).

### Use the rate limit with penalty

The Upstash Rate Limiting function keeps its counters in an Upstash Global Database. It therefore counts every request across the network, not in each data center. A request during a penalty receives `403 Forbidden`. A valid request is counted, and the function returns `429 Too Many Requests` when the count reaches the limit.

To set it up in Azion Console:

1. **Install the integration**

   Access [Azion Console](https://console.azion.com/) > **Marketplace**, search for `Upstash Rate Limiting`, and select **Install**.

2. **Open the firewall**

   Go to **Firewalls**, and open a firewall with **Functions** turned on in **Modules**.

3. **Create the function instance**

   In the **Functions Instances** tab, create an instance. In **Function**, select the Upstash Rate Limiting function, and edit the JSON **Arguments**.

4. **Run the function**

   In the **Rules Engine** tab, create a rule with criteria such as `Host` *matches* `yourdomain.com`, and the *Run Function* behavior with the instance.

5. **Bind the firewall to the workload**

   Run the CLI command that creates the workload deployment with the firewall:

   ```bash
   azion create workload-deployment --workload-id <workload-id> --name <deployment-name> --application-id <application-id> --firewall-id <firewall-id> --strategy-type default --active true --current true
   ```

The function counts the requests the rule matches. These arguments set a sliding window of 2 requests per 20 seconds from midnight to noon UTC, with a 45-second penalty:

```json
{
  "upstash_redis_rest_url": "https://your-database.upstash.io",
  "upstash_redis_rest_token": "<your-upstash-token>",
  "rate_limit_prefix": "my_rate_limit",
  "rate_limit_key_metadata": ["remote_addr"],
  "rate_limit_key_header": ["x-a-custom-header"],
  "rate_limit_key_hostname": true,
  "rate_limit_repenalize": true,
  "rate_limits": [
    {
      "algorithm": "sliding_window",
      "requests": 2,
      "interval": "20 s",
      "start": "00:00",
      "end": "12:00",
      "penalty_in_seconds": 45
    }
  ]
}
```

| Argument                                             | Description                                                                                                             |
| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `upstash_redis_rest_url`, `upstash_redis_rest_token` | The REST URL and the token of the Upstash database that stores the counters and the penalties                           |
| `rate_limit_prefix`                                  | A prefix for every key, which keeps two instances of the function apart                                                 |
| `rate_limit_key_metadata`                            | The request metadata that forms the key, such as `remote_addr`                                                          |
| `rate_limit_key_header`                              | The headers that form the key                                                                                           |
| `rate_limit_key_hostname`                            | When `true`, the hostname is part of the key                                                                            |
| `rate_limit_repenalize`                              | When `true`, every request during a penalty restarts it                                                                 |
| `rate_limits`                                        | The windows, at least one. When two windows overlap, the first one in the list applies                                  |
| `algorithm`                                          | `fixed_window`, `sliding_window`, or `token_bucket`                                                                     |
| `requests`                                           | The requests allowed in the interval                                                                                    |
| `interval`                                           | The window, as a number and `s` or `m`. For example: `"120 s"`                                                          |
| `start`, `end`                                       | The time of day the window covers, in 24-hour UTC. They default to `00:00` and `23:59`                                  |
| `penalty_in_seconds`                                 | How long a client that exceeds the limit receives `403`. Without it, the window is a plain rate limit                   |
| `max_tokens`, `refil_rate`                           | The bucket size and the refill per interval of a `token_bucket` window. `refil_rate` is the spelling the function reads |

The key joins the prefix and every value the arguments select. In this example, it is `my_rate_limit + client IP + x-a-custom-header value + hostname`, such as `my_rate_limit_127.0.0.1_Value_azion.com`. For the full setup, refer to [Install the Upstash Rate Limiting integration](/en/documentation/guides/application-development/integrations/upstash-rate-limiting-integration/).

---

## Rebuild monitoring

Azion splits observability across three products. [Real-Time Metrics](/en/documentation/platform/real-time-metrics/) charts aggregates over time, [Real-Time Events](/en/documentation/platform/real-time-events/) answers queries about individual requests, and [Data Stream](/en/documentation/platform/data-stream/) sends the logs to external destinations. Rebuild them before the cutover, so production visibility, troubleshooting, and compliance reporting continue after it.

### Real-Time Metrics

| Aspect          | Akamai TrafficPeak and reports                      | Azion Real-Time Metrics                                                           |
| --------------- | --------------------------------------------------- | --------------------------------------------------------------------------------- |
| Scope           | Traffic, operations, and security reporting         | Requests, data transferred, status codes, cache offload, and average request time |
| Access          | Akamai UI and APIs                                  | Dashboards, **Copy query**, **Export CSV**, and the GraphQL API                   |
| Use cases       | Traffic trends, security visibility, and operations | Traffic trends, cache offload, errors, and origin errors                          |
| Migration focus | Dashboard and alert parity                          | Dashboards, filters, GraphQL queries, and Grafana if needed                       |

The Applications dashboards chart:

- **Requests**: total requests, and requests by method and by scheme. **Average Request Time** is the average time, in seconds, that Azion takes to process and answer a request.
- **Status Codes**: the 2XX, 3XX, 4XX, and 5XX responses. The **Requests by Status and Upstream Status** table tells errors from Azion and errors from the origin apart.
- **Data Transferred**: saved and missed data and bandwidth, and **Edge Offload**.
- Cache: **Requests Offloaded**, **Saved Requests**, and **Missed Requests**.

To read the cache status of the requests, filter a dashboard by **Upstream Cache Status**, whose values include `HIT`, `MISS`, `STALE`, and `EXPIRED`. To find origin errors, filter by **Upstream Status**, which is `0` when the origin did not answer.

To open the dashboards, access [Azion Console](https://console.azion.com/) > **Real-Time Metrics**. It opens on **Build** > **Applications** > **Data Transferred**, over the **Last 5 minutes**. To narrow a dashboard to one workload, add the **Domain** or **Workload** filter. To export a chart, open its **More options** menu and select **Export CSV**.

To query the same data, send a GraphQL query to `https://api.azion.com/v4/metrics/graphql`:

```graphql
query {
  workloadMetrics(limit: 10, filter: { tsRange: {begin: "2026-10-01T00:00:00", end: "2026-10-02T00:00:00"} }, aggregate: { sum: requests }, groupBy: [ts], orderBy: [ts_DESC]) {
    ts
    sum
  }
}
```

The response lists the total requests per timestamp. Replace the dates with a range inside the retention period, or the array comes back empty. The `httpMetrics` dataset of older queries still works, but it is deprecated. For every field, refer to [Real-Time Metrics GraphQL fields](/en/documentation/devtools/graphql/gql-real-time-metrics-fields/). To read the dashboards, refer to [Real-Time Metrics quickstart](/en/documentation/platform/real-time-metrics/quickstart/), [Analyze metrics](/en/documentation/guides/platform/observability/analyze-metrics/), and [Grafana plugin custom dashboards](/en/documentation/guides/platform/observability/azion-plugin-grafana-custom-dash/).

### Real-Time Events

| Aspect     | Akamai investigation workflows               | Azion Real-Time Events                                 |
| ---------- | -------------------------------------------- | ------------------------------------------------------ |
| Access     | Akamai product dashboards, reports, and logs | Queries in Azion Console or the GraphQL API            |
| Data model | Akamai product log fields                    | Data sources with the fields of each event             |
| Querying   | Product-specific filters                     | **Filter by** conditions in Azion Console, and GraphQL |

Real-Time Events needs no setup. An event is queryable up to 30 seconds after it happens, and stays for 7 days. For longer retention, use Data Stream. Its data sources are **HTTP Requests**, **Functions**, **Functions Console**, **Image Processor**, **Tiered Cache**, **Edge DNS**, **Data Stream**, and **Activity History**. WAF results are fields of **HTTP Requests**.

To query the events in Azion Console:

1. **Open Real-Time Events**

   Access [Azion Console](https://console.azion.com/) > **Products menu** > **Observe** > **Real-Time Events**.

2. **Select the data source**

   Select the data source, such as **HTTP Requests**.

3. **Set the time and the filters**

   Set the **Time Filter**, which opens on the last 15 minutes, and add conditions in **Filter by**.

4. **Select Refresh**

The results table lists the events. Select a row to open the whole record.

To query the same data, send a GraphQL query to `https://api.azion.com/v4/events/graphql`. The `workloadEvents` dataset holds the HTTP requests:

```graphql
query {
  workloadEvents(
    limit: 100
    filter: { tsRange: { begin: "2026-10-07T00:00:00", end: "2026-10-07T01:00:00" } }
    orderBy: [ts_DESC]
  ) {
    ts
    remoteAddress
    requestUri
    status
    upstreamResponseTime
  }
}
```

The response lists up to 100 requests, newest first. Replace the dates with a range inside the last 7 days. `upstreamResponseTime` reads `-` for a response served from cache. For every field, refer to [Real-Time Events GraphQL fields](/en/documentation/devtools/graphql/gql-real-time-events-fields/). For the steps, refer to [Real-Time Events quickstart](/en/documentation/platform/real-time-events/quickstart/), [Investigate requests with the GraphQL API](/en/documentation/guides/platform/observability/investigate-requests-graphql-api/), and [Read an event record](/en/documentation/guides/platform/observability/understand-logs/).

### Data Stream

| Aspect       | Akamai DataStream                       | Azion Data Stream                                                 |
| ------------ | --------------------------------------- | ----------------------------------------------------------------- |
| Delivery     | Log streaming to configured endpoints   | Push to an external destination                                   |
| Format       | Stream and destination-specific formats | Templates that select the fields                                  |
| Destinations | External logging and storage services   | 11 types, listed below                                            |
| Sources      | Akamai property or product logs         | *Activity History*, *Applications*, *Functions*, and *WAF Events* |

A stream sends one data source to one destination:

- **Storage**: Amazon S3, Azure Blob Storage, and Azion Object Storage, through the S3 type.
- **Monitoring**: Datadog, Splunk, Elasticsearch, and Azure Monitor.
- **Streaming**: AWS Kinesis Data Firehose and Apache Kafka.
- **Analytics**: Google BigQuery.
- **Security**: IBM QRadar.
- **Custom**: Standard HTTP/HTTPS POST.

A stream needs exactly one of sampling or a workload filter. Saving an active sampled stream deactivates every other stream on the account. Filtered streams coexist.

**Console**

To create a stream in Azion Console:

1. **Open Data Stream**

   Access [Azion Console](https://console.azion.com/) > **Data Stream**.

2. **Select + Stream**

3. **Select the data source**

   In **Input**, select the **Data Source**: *Activity History*, *Applications*, *Functions*, or *WAF Events*.

4. **Select the template**

   In **Render Template**, select the **Template**.

5. **Select the destination**

   In **Output**, select the **Connector**, such as *Simple Storage Service (S3)*, and enter its credentials.

6. **Turn on Active and select Save**

The stream starts sending after 1 to 2 minutes.

**CLI**

To create a stream with the Azion CLI, follow the CLI panel of the [Data Stream quickstart](/en/documentation/platform/data-stream/quickstart/).

**API**

To create a stream, send a `POST` request to `https://api.azion.com/v4/workspace/stream/streams`. The body has `inputs`, `transform`, and `outputs`:

```json
{
  "name": "akamai-migration-log-stream",
  "active": true,
  "inputs": [
    { "type": "raw_logs", "attributes": { "data_source": "activity_history" } }
  ],
  "transform": [
    { "type": "sampling", "attributes": { "rate": 100 } },
    { "type": "render_template", "attributes": { "template": 251 } }
  ],
  "outputs": [
    {
      "type": "s3",
      "attributes": {
        "host_url": "https://s3.us-east-005.azionstorage.net",
        "bucket_name": "<your-bucket>",
        "region": "us-east-005",
        "access_key": "[ACCESS KEY]",
        "secret_key": "[SECRET KEY]",
        "object_key_prefix": "activity",
        "content_type": "plain/text"
      }
    }
  ]
}
```

A `POST` returns `201`. For an Applications stream, use `"data_source": "workloads"`. Without sampling or a workload filter, the create fails with `32002`, and with both it fails with `32007`. Templates are created at `/v4/workspace/stream/templates`.

If logs do not reach the destination, check the stream status, the destination credentials, and the template variables. For an Object Storage destination, the credential needs `listAllBucketNames`, `listBuckets`, `listFiles`, and `writeFiles`, or every send fails with `503`. For the fields, refer to [Stream settings](/en/documentation/platform/data-stream/stream-settings/), [Data sources and variables](/en/documentation/platform/data-stream/data-sources-and-variables/), and [Configure sampling](/en/documentation/guides/platform/observability/configure-sampling/).

---

## Move mPulse to Edge Pulse

[Edge Pulse](/en/documentation/platform/edge-pulse/) measures from the browsers of real visitors, the role mPulse plays. A JavaScript tag on each page runs a test and sends the result to Azion. A test measures navigation, availability, latency, and bandwidth.

| Aspect          | Akamai mPulse                                                     | Azion Edge Pulse                                                          |
| --------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------- |
| Collection      | Real-user monitoring tag                                          | Edge Pulse JavaScript tag: the **Default Tag** or the **Pre-loading Tag** |
| Use cases       | User experience, latency, availability, and performance analytics | Navigation, availability, latency, and bandwidth from real visitors       |
| Analysis        | mPulse dashboards and exports                                     | GraphQL queries on the `pulseEvents` dataset of Real-Time Events          |
| Migration focus | Beacon placement, dashboards, and alert logic                     | Tag placement, data checks, and query-based dashboards                    |

Edge Pulse is active on every account, and the tag needs no setup. No page of Azion Console charts the measurements, and Real-Time Metrics and Data Stream do not carry them. A query on `pulseEvents` is the only way to read them, and they last 7 days. The tag has no settings, and it measures one visitor once every 30 minutes.

To move the monitoring:

1. List every page template, tag manager rule, or application shell that loads mPulse.
2. Document the metrics, dimensions, dashboards, and alerts the team uses.
3. In Azion Console, access **Products menu** > **Observe** > **Edge Pulse**, and copy the **Default Tag**. Copy the **Pre-loading Tag** instead when the Content Security Policy of the page blocks inline JavaScript.
4. Paste the tag immediately before the closing `body` tag of each page, by hand or through a tag management system, and publish the pages.

Each published page now measures its visitors. To check that measurements arrive, average the page load time per page:

```bash
curl -X POST https://api.azion.com/v4/events/graphql \
  -H "Authorization: Token [TOKEN VALUE]" \
  -H "Content-Type: application/json" \
  -d '{"query": "query { pulseEvents(limit: 100, filter: { tsRange: {begin: \"2026-10-04T00:00:00\", end: \"2026-10-05T00:00:00\"} }, aggregate: { avg: pageloadtime }, groupBy: [locationhref], orderBy: [avg_DESC]) { locationhref avg } }"}'
```

The endpoint returns `200`, with one object per tagged page that had visits in the window. A window with no measurements returns an empty array. Replace the dates with a range inside the last 7 days. A tagged page with visits and no row is a page where the tag does not run, because the tag reports no error.

A single-page application is measured once per full page load. Rebuild the mPulse dashboards and alerts as queries on `pulseEvents`, in a custom dashboard or an observability platform. For the steps, refer to [Edge Pulse quickstart](/en/documentation/platform/edge-pulse/quickstart/), [How Edge Pulse works](/en/documentation/platform/edge-pulse/how-it-works/), and [Query Edge Pulse measurements with GraphQL](/en/documentation/guides/platform/observability/query-edge-pulse-measurements-with-graphql/).

---

## Prepare the certificate

[Certificate Manager](/en/documentation/platform/workloads/certificate-manager/quickstart/) holds the certificates that workloads serve. Prepare the certificate before the hostname points to Azion, so users reach the property over HTTPS from the first request.

| Certificate option     | Use it for                                                                                                         |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------ |
| Let's Encrypt          | A managed certificate for your own domains, at no additional cost. It renews from 30 days before its 90-day expiry |
| Custom certificate     | A certificate you already have, single-domain or SAN, with RSA 2048 or P-256 keys. You manage its renewal          |
| Azion SAN              | The `azionedge.net` workload domain and the `azion.app` hostname                                                   |
| Trusted CA certificate | mTLS. Azion SAN does not support mTLS                                                                              |

Pick the Let's Encrypt challenge by where DNS answers:

- **HTTP-01** needs the hostname, and every alternative name, to already point to Azion.
- **DNS-01** works before the move. At an external DNS provider, add a CNAME from `_acme-challenge.<domain>` to `<domain>.letsencrypt.azion.com`. In Edge DNS, the record is automatic.

For a move from Akamai, use DNS-01.

**Console**

To request the certificate in Azion Console:

1. **Open the workload**

   Access [Azion Console](https://console.azion.com/) > **Workloads**, then select or create the workload.

2. **Enter the domains**

   In **Domains**, enter each hostname the property answers to. Wildcards are refused.

3. **Turn on HTTPS**

   In **Protocol Settings**, turn on **HTTPS support**.

4. **Select the certificate**

   In **Digital Certificate**, select *New Let's Encrypt Certificate (DNS-01)*.

5. **Select Save**

The first attempt runs up to 5 minutes after you save. Retries follow at 5, 10, 15, 20, and 30 minutes, then on a slower schedule. The status moves from `pending` to `challenge_verification`, then to `active` or `failed`.

To upload a certificate you already have, access **Certificate Manager** and create a digital certificate with the **Server Certificate** preset. Paste the PEM certificate and the private key. Intermediate certificates go in the same field as the certificate. Then select it in the **Digital Certificate** field of the workload. For every field, refer to [Certificates](/en/documentation/platform/workloads/certificate-manager/certificates/).

**CLI**

To set the certificate of a workload with the Azion CLI, run `azion update workload --file` with the workload body. For the certificate commands, refer to [Certificate Manager quickstart](/en/documentation/platform/workloads/certificate-manager/quickstart/).

**API**

To request a Let's Encrypt certificate, send a `POST` request to `https://api.azion.com/v4/workspace/tls/certificates/request`. The body takes `name`, `"authority": "lets_encrypt"`, `challenge` (`http` or `dns`), `common_name`, and optional `alternative_names`. To upload your own certificate, send `name`, `"type": "edge_certificate"`, `certificate`, and `private_key` to `/v4/workspace/tls/certificates`. Each PEM is one JSON string with `\n` line breaks, and the API answers `201`.

To serve the certificate, set its ID in `tls.certificate` of the workload, or `null` for Azion SAN:

```json
{
  "name": "my-workload",
  "active": true,
  "infrastructure": 1,
  "domains": ["www.example.com"],
  "tls": { "certificate": 12345, "ciphers": 4, "minimum_version": "tls_1_2" }
}
```

`infrastructure` `1` is production. `minimum_version` takes `tls_1_0`, `tls_1_1`, `tls_1_2`, or `tls_1_3`, and defaults to `tls_1_3`. Send the body to `https://api.azion.com/v4/workspace/workloads`.

If the certificate does not become active, read its `status` and `status_detail`. For DNS-01, check the `_acme-challenge` CNAME. Confirm that the hostname is in the **Domains** of the right workload before the DNS change. For the issuance rules, refer to [Issuance and renewal](/en/documentation/platform/workloads/certificate-manager/issuance-and-renewal/).

---

## Move DNS zones to Edge DNS

Moving the zone to [Edge DNS](/en/documentation/platform/edge-dns/) gives Azion every record of the domain, including the apex. Every zone uses the same three nameservers, `ns1.aziondns.net`, `ns2.aziondns.com`, and `ns3.aziondns.org`. Move DNS only after the applications, workloads, certificates, and security rules answer as expected. Skip this stage when you keep the current DNS provider and point only subdomains.

| Aspect              | Akamai                                                    | Azion                                                          |
| ------------------- | --------------------------------------------------------- | -------------------------------------------------------------- |
| Authoritative DNS   | Edge DNS and DNS Manager                                  | Edge DNS                                                       |
| Traffic steering    | Global Traffic Management                                 | Weighted records in Edge DNS, and Load Balancer on a connector |
| Application routing | DNS records and Global Traffic Management properties      | Workloads, Edge DNS, and Load Balancer                         |
| Validation          | DNS tools, Global Traffic Management tests, and reporting | `dig`, Real-Time Metrics, and Real-Time Events                 |

Edge DNS supports 11 record types: A, AAAA, ANAME, CAA, CNAME, DS, MX, NS, PTR, SRV, and TXT. An ANAME aliases the apex to an Azion hostname, such as the workload domain, and its TTL must be 20. A CNAME holds exactly one value and cannot sit at the apex. Edge DNS refuses other types, such as SOA.

To split answers between targets, the way Global Traffic Management steers traffic, use weighted records. With **Policy Type** *Weighted*, several records share one name and type, each with a **Weight** from 0 to 255. Each answer carries one record, chosen in proportion to its weight. A record's policy is either *Simple* or *Weighted*.

**Console**

To create the zone in Azion Console:

1. **Open Edge DNS**

   Access [Azion Console](https://console.azion.com/) > **Edge DNS**.

2. **Select + Zone**

3. **Enter the zone**

   Enter a **Name** for the zone, and the **Domain Name**. The domain cannot change after the zone is created.

4. **(Optional) Turn on DNSSEC**

   Under **DNSSEC**, turn on **Enable DNSSEC**.

5. **Select Save**

6. **Add the records**

   In the **Records** tab, create each record of the Akamai zone.

The zone answers on the Azion nameservers. For the steps, refer to [Create, edit, or delete a zone](/en/documentation/guides/application-security/dns/edge-dns-configure-main-settings/) and [Add, edit, or delete a record](/en/documentation/guides/application-security/dns/add-records/).

**CLI**

To create zones and records with the Azion CLI, follow the CLI panel of the [Edge DNS quickstart](/en/documentation/platform/edge-dns/quickstart/). Boolean flags need `=`, such as `--active=false`.

**API**

To create the zone and a record, send `POST` requests to the zones endpoint:

```bash
curl -X POST https://api.azion.com/v4/workspace/dns/zones \
  -H "Authorization: Token [TOKEN VALUE]" \
  -H "Content-Type: application/json" \
  -d '{"name":"example-zone","domain":"example.com","active":true}'
```

```bash
curl -X POST https://api.azion.com/v4/workspace/dns/zones/<zone-id>/records \
  -H "Authorization: Token [TOKEN VALUE]" \
  -H "Content-Type: application/json" \
  -d '{"name":"www","type":"A","rdata":["192.0.2.1"],"ttl":3600}'
```

A record takes its `name` relative to the zone, its `type`, and `rdata` as an array of strings. A weighted record adds `"policy": "weighted"` and a `weight`. To turn on DNSSEC, send `{"enabled": true}` in a `PATCH` request to `/v4/workspace/dns/zones/<zone-id>/dnssec`.

Before the cutover window, export the zones, records, TTLs, DNSSEC settings, and traffic steering rules from Akamai, and lower the TTLs. With DNSSEC on, Edge DNS shows four DS values to add at the registrar, which can take up to 48 hours to publish them. For the steps, refer to [DNSSEC](/en/documentation/platform/edge-dns/dnssec/).

To check the zone, query the nameservers and the records:

```bash
dig example.com NS +short
dig @ns1.aziondns.net example.com A
```

The first command lists the three Azion nameservers once the registrar change propagates. The second shows the answer of Edge DNS before the change reaches every resolver. Do not query a new name before its record exists: Edge DNS caches the negative answer for one hour.

---

## Point the domain to the workload

The DNS change is the switch: once the hostname resolves to the workload, users reach the property through Azion. Treat it as a controlled cutover. It affects users, search rankings, certificate coverage, and availability. Before you switch, confirm that:

- The certificate is active.
- The hostname is in the **Domains** of the workload.
- The DNS records are ready.
- The critical routes and the redirects answer as expected on the workload domain. To test them under the real hostname first, refer to [Test an application through the hosts file](/en/documentation/guides/application-development/getting-started/stage-applications-through-hosts-file/).
- The firewall is bound to the workload.
- Monitoring is ready to watch the traffic after the switch.

Point each name with the record its zone allows:

| Strategy    | Use it for                                                          | Record                                      |
| ----------- | ------------------------------------------------------------------- | ------------------------------------------- |
| CNAME       | A subdomain, keeping the current DNS provider                       | `www CNAME <your-workload-domain>`          |
| Nameservers | The apex and every other name, with Edge DNS answering for the zone | An ANAME at the apex to the workload domain |

To check a CNAME and the response:

```bash
dig www.example.com CNAME +short
curl -I https://www.example.com/
```

The first answer is the workload domain, such as `xxxxxxxxxx.map.azionedge.net`. The second is the response of the property through Azion. If traffic does not move, check the TTLs, the CNAME records, the nameservers, and the hostname in the workload. After the switch, watch Real-Time Metrics and Real-Time Events, and the **Upstream Status** of the origin.

For the Console settings of the custom domain, refer to [Point a domain to a workload](/en/documentation/guides/platform/migration/point-domain-to-azion/) and [Workloads](/en/documentation/platform/workloads/). To move the nameservers, refer to [Migrate the nameservers to Azion](/en/documentation/guides/platform/migration/migrate-ns-to-azion/).

---

## Next steps

- [Real-Time Metrics](/en/documentation/platform/real-time-metrics/quickstart.md): Watch requests, data transferred, status codes, and cache offload after the switch.
- [Edge Pulse](/en/documentation/platform/edge-pulse/quickstart.md): Tag the pages that carried mPulse, and query what real visitors measure.
- [Web Application Firewall](/en/documentation/platform/firewall/waf/quickstart.md): Move the rule set from Logging to Blocking once the traffic is clean.
- [Azion CLI](/en/documentation/devtools/cli.md): Deploy, purge, read logs, and manage the property from a terminal.
- [Azion community](https://discord.gg/azion): Ask the Azion community on Discord how others run their properties on Azion.
- [Azion Support](/en/documentation/support.md): Open a ticket with the support team when the migration needs help.
