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

# Go Quickstart

> Generate a typed Go client from your schema and publish your first event with idempotency and explicit lifecycle ownership.

export const RepostHighlight = () => {
  useEffect(() => {
    const colors = {
      comment: ['#116329', '#6A9955'],
      constant: ['#0550AE', '#9CDCFE'],
      keyword: ['#CF222E', '#569CD6'],
      name: ['#953800', '#4EC9B0'],
      string: ['#0A3069', '#CE9178'],
      type: ['#0550AE', '#4EC9B0'],
      variable: ['#1F2328', '#9CDCFE']
    };
    const tokenPattern = /"[^"\n]*"|@[A-Za-z_]\w*|\b(?:String|Int|Float|Boolean|DateTime|Json)\b|\b(?:true|false)\b|\b\d+(?:\.\d+)?\b|\b(?:now|uuid|cuid)(?=\s*\()|\b[A-Z]\w*\b|\b[A-Za-z_]\w*\b/g;
    const append = (line, text, color) => {
      if (!text) return;
      if (!color) {
        line.append(text);
        return;
      }
      const span = document.createElement('span');
      span.textContent = text;
      span.style.color = color[0];
      span.style.setProperty('--shiki-dark', color[1]);
      line.append(span);
    };
    const commentStart = text => {
      let quoted = false;
      for (let index = 0; index < text.length - 1; index += 1) {
        if (text[index] === '"' && text[index - 1] !== '\\') quoted = !quoted;
        if (!quoted && text[index] === '/' && text[index + 1] === '/') return index;
      }
      return -1;
    };
    const highlightCode = code => {
      if (code.dataset.repostHighlighted !== undefined || code.querySelector('span[style*="--shiki-dark"]')) {
        return;
      }
      code.dataset.repostHighlighted = '';
      const source = code.textContent ?? '';
      const fragment = document.createDocumentFragment();
      for (const text of source.split('\n')) {
        const line = document.createElement('span');
        line.className = 'line';
        const declaration = text.match(/^(\s*)(generator|model|enum|type|event)(\s+)([A-Za-z_]\w*)(.*)$/);
        if (declaration) {
          append(line, declaration[1]);
          append(line, declaration[2], colors.keyword);
          append(line, declaration[3]);
          append(line, declaration[4], colors.name);
          append(line, declaration[5]);
        } else {
          const start = commentStart(text);
          const codeText = start === -1 ? text : text.slice(0, start);
          const leading = codeText.match(/^(\s*)([A-Za-z_]\w*)(?=\s+(?:@|[A-Z]))/);
          const bare = codeText.match(/^(\s*)([A-Za-z_]\w*)(\s*)$/);
          let offset = 0;
          for (const match of codeText.matchAll(tokenPattern)) {
            append(line, codeText.slice(offset, match.index));
            const token = match[0];
            let color = colors.constant;
            if (token.startsWith('"')) color = colors.string; else if (token.startsWith('@') || (/^(now|uuid|cuid)$/).test(token)) color = colors.name; else if ((/^(String|Int|Float|Boolean|DateTime|Json)$/).test(token)) color = colors.type; else if (leading && match.index === leading[1].length) color = colors.variable; else if (bare && match.index === bare[1].length) color = colors.constant; else if ((/^[A-Z]/).test(token)) color = colors.name; else if ((/^[A-Za-z_]/).test(token)) color = colors.variable;
            append(line, token, color);
            offset = match.index + token.length;
          }
          append(line, codeText.slice(offset));
          if (start !== -1) append(line, text.slice(start), colors.comment);
        }
        fragment.append(line, '\n');
      }
      code.replaceChildren(fragment);
    };
    const highlightRepostBlocks = () => {
      for (const block of document.querySelectorAll('.code-block')) {
        const code = block.querySelector('pre code');
        const filename = block.querySelector('[data-component-part="code-block-header-filename"] [title$=".repost"]');
        const looksLikeRepost = (/^\s*(generator|model|enum|type|event)\s+[A-Za-z_]\w*\s*\{/m).test(code?.textContent ?? '');
        if (code && (filename || looksLikeRepost)) highlightCode(code);
      }
    };
    let frame;
    const schedule = () => {
      if (frame !== undefined) return;
      frame = requestAnimationFrame(() => {
        frame = undefined;
        highlightRepostBlocks();
      });
    };
    const observer = new MutationObserver(schedule);
    observer.observe(document.documentElement, {
      childList: true,
      subtree: true
    });
    schedule();
    return () => {
      observer.disconnect();
      if (frame !== undefined) cancelAnimationFrame(frame);
    };
  }, []);
  return null;
};

<RepostHighlight />

The Repost CLI turns your `.repost` schema into a Go package with model structs, enum constants, and typed methods under `client.Webhooks`. The generated package uses `github.com/repost-sh/repost-go` for validation, serialization, retries, transport, and delivery outcomes. The client requires Go 1.25 or later and belongs only in trusted server-side code.

<Steps>
  <Step title="Install the runtime">
    Add the runtime to your module:

    ```bash theme={"languages":{"custom":["/languages/repost.json"]}}
    go get github.com/repost-sh/repost-go@v0.3.0
    ```
  </Step>

  <Step title="Create a schema workspace">
    ```bash theme={"languages":{"custom":["/languages/repost.json"]}}
    repost schema init --language go --output ../internal/repostclient
    ```

    The command creates `repost/schema.repost` and `.env`. A Go generator always needs an explicit output because the generated package is committed with your application.

    ```jssm repost/schema.repost theme={"languages":{"custom":["/languages/repost.json"]}}
    generator sdk {
      language = "go"
      output   = "../internal/repostclient"
    }

    model Order {
      id String
    }

    type Order {
      created
    }

    event OrderCreated {
      type      @type(Order.created)
      data      Order
      timestamp DateTime
    }
    ```
  </Step>

  <Step title="Record the schema and generate">
    ```bash theme={"languages":{"custom":["/languages/repost.json"]}}
    repost schema migrate dev --name init
    ```

    This records the first migration and generates `internal/repostclient`. Commit the migration, schema, and generated package together.
  </Step>

  <Step title="Connect an environment">
    Create an environment in the [dashboard](https://app.repost.sh), then put its publish API key in the `.env` file created by `schema init`:

    ```dotenv theme={"languages":{"custom":["/languages/repost.json"]}}
    REPOST_SEND_API_KEY=send_...
    ```

    Sign in and deploy the migration before sending the new event type:

    ```bash theme={"languages":{"custom":["/languages/repost.json"]}}
    repost auth login
    repost schema migrate deploy
    ```

    Load `.env` through your process manager or deployment platform. The Go runtime reads process environment variables; it does not load `.env` files itself.
  </Step>
</Steps>

## Your first send

```go theme={"languages":{"custom":["/languages/repost.json"]}}
package main

import (
    "context"
    "log"

    repost "github.com/repost-sh/repost-go"
    "example.com/yourapp/internal/repostclient"
)

func main() {
    client, err := repostclient.NewClient(repost.ClientOptions{})
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    result, err := client.Webhooks.Order.Created(context.Background(), repostclient.OrderCreatedInput{
        CustomerID:     "customer_123",
        Data:           repostclient.Order{ID: "order_1001"},
        IdempotencyKey: "order_1001:created",
    })
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("accepted message %s", result.ID)
}
```

`CustomerID` is the external ID of the customer receiving the event. The generated input requires the correct model type, and the runtime validates the value before opening a connection.

The idempotency key is optional. Without one, the runtime creates a key and reuses it for that operation's internal retries. Supply a stable business key when a queue redelivery, process restart, or application retry can repeat the same logical send. See [Reliable sends](/docs/send/go/reliability) before adding your own retry loop.

Create one client for each application process. It owns bounded connection pools and an observer dispatcher. Close it during graceful shutdown rather than constructing and closing a client in every request handler.

## Continue

<Columns cols={3} className="gap-y-4">
  <Card title="Code generation" icon="cog" href="/docs/send/go/generation" cta="Generation" arrow="true">
    Generated files, optional values, regeneration, and version checks.
  </Card>

  <Card title="Configuration" icon="sliders-horizontal" href="/docs/send/go/configuration" cta="Configure" arrow="true">
    Credentials, deadlines, capacity, proxy, TLS, DNS, and HTTP/2.
  </Card>

  <Card title="Reliability" icon="shield-check" href="/docs/send/go/reliability" cta="Outcomes" arrow="true">
    Idempotency, delivery states, cancellation, retries, and backpressure.
  </Card>
</Columns>
