> ## Documentation Index
> Fetch the complete documentation index at: https://bunnynet-cb9733c2-docs-dns-cli-tabs-and-scriptable-types.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction

> The Scriptable DNS allows you to dynamically respond to DNS queries using JavaScript scripts. The following pages contain sample documentation to help you get started.

## Quickstart

Create a DNS script, test it, publish it, and attach it to a hostname in your zone.

<Tabs>
  <Tab title="Dashboard">
    <Steps>
      <Step title="Create a DNS Script">
        In the bunny.net dashboard, go to [**DNS Scripts**](https://dash.bunny.net/dns/scripts) and click **Add DNS Script**.
      </Step>

      <Step title="Write your script">
        The Code editor opens with a starter script that answers every query with a TXT record:

        ```javascript theme={null}
        /*
            Handle the DNS query!
        */
        export default function handleQuery(event) {
            return new TxtRecord("Hello world!");
        }
        ```

        Edit the script to return the response you need, such as an `ARecord` for IP-based routing. See the [entry function](#entry-function) below for the query details available to your script.
      </Step>

      <Step title="Test it">
        Use the fields below the editor to simulate a query: set the **Type**, **Hostname**, **Client IP**, **EDNS IP**, and **Location**, then click **Run**.

        The **Response** panel shows the DNS response your script returned, so you can try different request parameters and evaluate how your script behaves. Output from `console.log` appears in the **Console** tab.
      </Step>

      <Step title="Publish the script">
        Click **Save** to store your changes, then **Publish** to make the script live.
      </Step>

      <Step title="Attach it to a DNS Zone">
        A script only answers queries once a record points at it:

        1. Go to **DNS** and select your DNS Zone
        2. Click **Add DNS Record**
        3. Enter a **Hostname**
        4. Select **SCR** as the **Type**
        5. Select the script you just published in the **Script** dropdown
        6. Click **Add Record**

        Queries for that hostname are now answered by your script.
      </Step>
    </Steps>
  </Tab>

  <Tab title="CLI">
    <Note>
      Don't have the CLI installed? See the [CLI quickstart](/cli/quickstart) to install and authenticate.
    </Note>

    <Steps>
      <Step title="Scaffold a project">
        ```bash theme={null}
        bunny dns scripts init hello-dns
        ```

        This writes a `handleQuery` entry file, a `tsconfig.json`, and a `package.json` with the [type definitions](#type-safety) preconfigured, and links the directory to the script. Pass `--example` to start from a template (`empty`, `geo`, `closest`, `weighted`, `failover`, `pullzone`).
      </Step>

      <Step title="Write your script">
        Edit the entry file to return the response you need. See the [entry function](#entry-function) below for the query details available to your script.
      </Step>

      <Step title="Deploy the script">
        Upload and publish the linked script's entry file:

        ```bash theme={null}
        bunny dns scripts deploy
        ```
      </Step>

      <Step title="Attach it to a DNS Zone">
        A script only answers queries once a record points at it. Add a `SCRIPT` record to a zone:

        ```bash theme={null}
        bunny dns scripts attach example.com api
        ```

        The command confirms before writing the record. Verify it by querying the record type your script answers:

        ```bash theme={null}
        dig api.example.com A
        ```
      </Step>
    </Steps>

    See the [`bunny dns` command reference](/cli/commands/dns) for the full list of script commands.
  </Tab>
</Tabs>

## Entry function

The Scriptable DNS pipeline executes through a statically defined function **handleQuery**.

To return a response to the query, you can return one of the DNS response objects as documented in the [Query Response Object Types](/dns/scriptable/query-response-object-types).

```javascript theme={null}
export default function handleQuery(query) {
  return new ARecord("111.111.111.111", 30);
}
```

<Warning>
  `console.log` is intended for use within the Script Editor only. Please remove
  all logging statements before saving or publishing, as they may cause your
  script to fail at runtime.
</Warning>

## Query object

The entry function is passed a DnsRequest object parameter called **query** that contains the information about the request, such as the hostname, country, remote IP, etc.

### DnsRequest

| Field     | Type     | Description                                                     |
| --------- | -------- | --------------------------------------------------------------- |
| `request` | DnsQuery | The DNS query request that contains the details about the query |

### DnsQuery

| Field         | Type        | Description                                                                  |
| ------------- | ----------- | ---------------------------------------------------------------------------- |
| `hostname`    | string      | The hostname that is being queried                                           |
| `clientIP`    | string      | The IP of the remote client that sent the DNS query                          |
| `queryType`   | string      | The query question type (A, AAAA, TXT)                                       |
| `ednsIP`      | string      | The EDNS0 IP of the DNS query that was attached by the client                |
| `geoLocation` | GeoLocation | The geo location of the client                                               |
| `serverZone`  | string      | The server zone of the DNS server that received the query (DE, UK, SG, etc.) |

### GeoLocation

| Field       | Type   | Description                                            |
| ----------- | ------ | ------------------------------------------------------ |
| `latitude`  | double | The latitude location of the client                    |
| `longitude` | double | The longitude location of the client                   |
| `country`   | string | The detected two letter ISO country code of the client |
| `asn`       | long   | The detected ASN number of the client                  |

## Type safety

The Scriptable DNS runtime injects its globals (such as `ARecord` and the other [response object types](/dns/scriptable/query-response-object-types)) directly into your script, and does not support `import`. The [`@bunny.net/scriptable-dns-types`](https://github.com/BunnyWay/cli/tree/main/packages/scriptable-dns-types) package provides ambient TypeScript declarations for these globals, giving you editor autocomplete and optional type checking without any runtime imports.

Install it as a development dependency:

```bash theme={null}
npm install --save-dev @bunny.net/scriptable-dns-types
```

Then reference the types from within your script file with a triple-slash directive:

```javascript theme={null}
/// <reference types="@bunny.net/scriptable-dns-types" />

/** @param {DnsRequest} query */
export default function handleQuery(query) {
  if (query.request.geoLocation.country === "DE") {
    return new ARecord("203.0.113.20", 30);
  }
  return new ARecord("203.0.113.10", 30);
}
```

Or enable them project-wide through `tsconfig.json`:

```json theme={null}
{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true,
    "noEmit": true,
    "types": ["@bunny.net/scriptable-dns-types"]
  }
}
```
