> ## Documentation Index
> Fetch the complete documentation index at: https://docs.basaltic.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Zone files

> Importing a BIND master file, and exporting one before a bulk change.

## Importing a zone file

`POST /v1/zones/{zone_id}/import` takes an RFC 1035 master file — the BIND
format every provider exports.

<Tip>
  If you are moving a live domain and your provider has no export, you may not
  need a file at all: `import_existing_records` at create time reads the records
  off them directly. See [Moving a live domain](/dns/ownership#moving-a-live-domain).
</Tip>

<Tabs>
  <Tab title="Console">
    Open the zone from **DNS** and choose **Import zone file**. Paste the file
    into the box, or load one from disk with **Choose a file**, then choose
    **Import**.

    The dialog then reports how many record sets it added and how many it
    replaced, and lists anything it skipped with the reason.
  </Tab>

  <Tab title="API">
    Send it as JSON in `zone_file`, or as the raw body under any other content
    type, so this works directly:

    ```bash theme={null}
    curl --data-binary @db.example.com \
      -H 'Content-Type: text/plain' \
      https://dns.basaltic.sh/v1/zones/{zone_id}/import
    ```
  </Tab>

  <Tab title="CLI">
    ```bash theme={null}
    basaltic dns zone import <zone-id> --zone-file "$(cat db.example.com)"
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    body, err := os.ReadFile("db.example.com")
    if err != nil {
        log.Fatal(err)
    }

    result, err := dns.New(cfg).ImportZoneFile(ctx, zoneID, &dns.ZoneImportRequest{
        ZoneFile: string(body),
    })
    ```
  </Tab>
</Tabs>

<AccordionGroup>
  <Accordion title="It merges, it never replaces" icon="git-merge">
    An RRset in the file replaces the RRset at the same name and type
    wholesale; an RRset the file does not mention is left exactly as it is.

    So an import **cannot delete a record**, and importing the same file twice
    is a no-op rather than an error — which is what makes it safe to retry.
  </Accordion>

  <Accordion title="It is all or nothing" icon="shield">
    The whole file is validated before a single record is written: every record
    faces the same type, name, TTL and rdata checks that creating one does, the
    same CNAME rule, and the same record quota. One bad record refuses the file
    and the zone is untouched.
  </Accordion>

  <Accordion title="Some records are skipped by design" icon="filter">
    The SOA and apex NS set are the platform's — the zone is served by our
    nameservers, and the apex NS is what the parent delegates to. The DNSSEC
    records (`RRSIG`, `DNSKEY`, `DS`, `NSEC`, `NSEC3`, `NSEC3PARAM`, `CDS`,
    `CDNSKEY`) are generated by our signer from keys your file cannot know.
    Records placed outside the zone are skipped too.

    Every one comes back in `skipped` with a reason. A file exported from a
    signed zone carries all of them, so refusing the file over them would make
    export/import unusable.
  </Accordion>
</AccordionGroup>

The file is capped at **1 MiB**. On success the SOA serial advances once for
the whole import.

## Exporting a zone file

`GET /v1/zones/{zone_id}/export` returns the zone as an RFC 1035 master file —
the same format `/import` takes.

<Tabs>
  <Tab title="Console">
    Open the zone from **DNS** and choose **Export zone file**. It downloads as
    `db.<zone name>`.
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    curl -H "$AUTH" https://dns.basaltic.sh/v1/zones/$ZONE_ID/export \
      -o db.example.com
    ```
  </Tab>

  <Tab title="CLI">
    ```bash theme={null}
    basaltic dns zone export <zone-id> > db.example.com
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    r, err := dns.New(cfg).ExportZoneFile(ctx, zoneID)
    if err != nil {
        log.Fatal(err)
    }
    defer r.Close()

    f, err := os.Create("db.example.com")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    _, err = io.Copy(f, r)
    ```

    The export streams, so copy it rather than reading it all into memory.
  </Tab>
</Tabs>

<Tip>
  **Take one before a bulk change.** The import merges and never deletes, so
  without a file captured beforehand there is no way back to the previous
  state.
</Tip>

<Warning>
  **The file cannot describe the whole zone**, and says so in its own header. A
  zone file carries records and nothing else, so these are not in it:

  * private-zone VPC associations

  Re-importing restores the records. Anything above has to be set up again.
</Warning>

The DNSSEC records are omitted — they sign keys held by this platform and mean
nothing anywhere else; a zone imported elsewhere is signed by whoever serves
it. The SOA and apex NS are included, as in any zone file, and an importer
replaces them with its own.
