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

# Quickstart

> Run a local Varianz registry, instrument one function with a VPoint, and override it from a test — in Python, TypeScript, Go, Java, or Kotlin.

This page takes you from zero to a passing Varianz test: a local registry, one instrumented function, and a test that overrides its result.

## Prerequisites

* Docker (to run the local registry)
* One of the supported languages: Python 3.10+, Node.js 22+, Go, or JDK 17+ for Java/Kotlin
* Access to the Varianz registry image (see [Running the registry locally](/reference/local-registry); the SDK packages need no credentials)

<Steps>
  <Step title="Run a local registry">
    The registry is the coordination service every SDK connects to. For local development, run it in-memory with plaintext enabled:

    ```bash theme={null}
    docker run --rm -p 50051:50051 \
      -e REGISTRY_INSECURE_PLAINTEXT=true \
      us-docker.pkg.dev/varianz-dist/registry/registry-server:v0.2.1
    ```

    It logs `LocalRegistry listening on http://[::]:50051` once ready. See [Running the registry locally](/reference/local-registry) for TLS and Postgres-backed options.
  </Step>

  <Step title="Install the SDK">
    All Varianz packages are served from `pkgs.varianz.io` — no credentials needed. Pick your language:

    <CodeGroup>
      ```bash Python theme={null}
      pip install "varianz==0.2.1" "varianz-pytest==0.2.1" \
        --extra-index-url https://pkgs.varianz.io/python/simple/
      ```

      ```bash TypeScript theme={null}
      echo '@varianz:registry=https://pkgs.varianz.io/npm/' >> .npmrc
      npm install --save @varianz/node@0.2.1
      npm install --save-dev @varianz/vitest@0.2.1
      ```

      ```bash Go theme={null}
      go get go.varianz.io/sdk@v0.2.1
      ```

      ```kotlin Java theme={null}
      // settings.gradle.kts
      pluginManagement {
          repositories {
              maven { url = uri("https://pkgs.varianz.io/maven") }
              gradlePluginPortal()
          }
      }

      // build.gradle.kts
      plugins { id("io.varianz.sdk") version "0.2.1" }
      repositories {
          mavenCentral()
          maven { url = uri("https://pkgs.varianz.io/maven") }
      }
      varianz { sdkVersion.set("0.2.1") }
      ```

      ```kotlin Kotlin theme={null}
      // build.gradle.kts — KSP must be applied before the Varianz plugin
      plugins {
          id("com.google.devtools.ksp") version "2.1.10-1.0.29"
          id("io.varianz.sdk.kotlin")
      }
      dependencies {
          ksp("com.github.javaparser:javaparser-core:3.27.0")
      }
      configure<io.varianz.gradle.kotlin.VarianzKotlinExtension> {
          sdkVersion.set("0.2.1")
      }
      ```
    </CodeGroup>

    Full per-ecosystem details (Maven, Docker, platform notes) are on the [Installation](/installation) page.
  </Step>

  <Step title="Instrument a function">
    Give one function a VPoint name. The SDK derives its schema from the function's types and registers it with the registry.

    <CodeGroup>
      ```python Python theme={null}
      from varianz import Varianz

      vz = Varianz("http://localhost:50051")

      @vz.vpoint(name="pricing/calculate")
      def calculate_price(amount: float, discount: float) -> float:
          return amount * (1 - discount)

      vz.register(calculate_price)
      ```

      ```typescript TypeScript theme={null}
      import { createVPoints, initRegistry } from '@varianz/node';

      initRegistry({
        endpoint: 'http://localhost:50051',
        applicationName: 'pricing-service',
      });

      const { instrumented } = createVPoints('pricing', {
        calculate(amount: number, discount: number): number {
          return amount * (1 - discount);
        },
      });

      // Call through `instrumented` so stages can intercept:
      instrumented.calculate(100, 0.1);
      ```

      ```go Go theme={null}
      var vz = varianz.New(varianz.WithEndpoint("http://localhost:50051"))

      type PricingRequest struct {
          Amount   float64
          Discount float64
      }

      var CalculatePrice = varianz.VPoint(vz, "pricing/calculate",
          func(ctx context.Context, req PricingRequest) (float64, error) {
              return req.Amount * (1 - req.Discount), nil
          },
      )

      func main() {
          if err := vz.Init(); err != nil {
              log.Fatal(err)
          }
          defer vz.Close()
          // CalculatePrice is the instrumented function — call it normally.
      }
      ```

      ```java Java theme={null}
      import io.varianz.annotations.vpoint.VPoint;
      import io.varianz.binding.RegistryBinding;

      public class PricingService {
          @VPoint(name = "pricing/calculate")
          public double calculatePrice(double amount, double discount) {
              return amount * (1 - discount);
          }
      }

      // At startup, before serving traffic:
      RegistryBinding.init("http://localhost:50051");
      PricingService service = new PricingService();
      PricingServiceVPoints.bind(service);  // generated by the annotation processor
      ```

      ```kotlin Kotlin theme={null}
      import io.varianz.annotations.vpoint.VPoint
      import io.varianz.binding.RegistryBinding

      class PricingService {
          @VPoint(name = "pricing/calculate")   // named arguments required in Kotlin
          fun calculatePrice(amount: Double, discount: Double): Double =
              amount * (1 - discount)
      }

      // At startup:
      RegistryBinding.init("http://localhost:50051")
      PricingServiceVPoints.bind(PricingService())
      ```
    </CodeGroup>
  </Step>

  <Step title="Enable the SDK">
    The SDK is **disabled by default** — an instrumented service with no configuration behaves as if Varianz weren't there. Clients are also secure by default: they always verify TLS unless you explicitly allow plaintext, so the second variable below is the opt-in for the local dev registry from step 1 and isn't used in TLS setups:

    ```bash theme={null}
    export VARIANZ_ENABLED=true
    export VARIANZ_INSECURE_ALLOW_PLAINTEXT=true  # local plaintext registry only
    ```

    Set both variables on the service process *and* on the test process. On startup the SDK logs one line confirming its state, e.g. `[varianz] ENABLED (source: env:VARIANZ_ENABLED)`.

    <Note>
      Java and Kotlin additionally need the `varianz-agent` attached for interception — the Gradle/Maven plugins do this automatically for test and run tasks. See [Configuration](/reference/configuration).
    </Note>
  </Step>

  <Step title="Override it from a test">
    Insert a CEL stage that replaces the function's result, wait for the service to confirm delivery, then call the function.

    <CodeGroup>
      ```python Python theme={null}
      # test_pricing.py — the `varianz` fixture comes from varianz-pytest
      from varianz import Varianz, cel

      def test_price_override(varianz):
          varianz.insert(cel("pricing/calculate", "42.0"))
          varianz.await_sync_or_fail(timeout_ms=5000)

          # In-process call: activate the session for this thread.
          # (Calls over HTTP/gRPC carry it in the x-varianz-id header instead.)
          Varianz.set_session(varianz.session_id)
          assert calculate_price(100.0, 0.1) == 42.0
      ```

      ```typescript TypeScript theme={null}
      // pricing.test.ts
      import { varianzVitest } from '@varianz/vitest';
      import { cel } from '@varianz/vitest';

      const { test } = varianzVitest({
        endpoint: 'http://localhost:50051',
        applicationName: 'pricing-tests',
      });

      test('price override', async ({ varianz }) => {
        await varianz.insert(cel('pricing/calculate', '42.0'));
        await varianz.awaitSyncOrFail(5_000);

        expect(instrumented.calculate(100, 0.1)).toBe(42);
      });
      ```

      ```go Go theme={null}
      func TestPriceOverride(t *testing.T) {
          session := varianztest.NewSession(t, "http://localhost:50051")

          session.Insert(varianztest.Cel("pricing/calculate", "42.0"))
          session.AwaitSyncOrFail(5 * time.Second)

          // Call the service with the session ID in context:
          ctx := varianz.WithSession(context.Background(), session.SessionID())
          got, err := CalculatePrice(ctx, PricingRequest{Amount: 100, Discount: 0.1})
          if err != nil || got != 42.0 {
              t.Fatalf("got %v, err %v", got, err)
          }
      }
      ```

      ```java Java theme={null}
      @ExtendWith(VarianzExtension.class)
      class PricingTest {
          @Test
          void priceOverride(VarianzSession session) {
              session.insert(cel("pricing/calculate", "42.0"));
              session.awaitSyncOrFail();

              // Trigger the service with session.sessionId() in the
              // x-varianz-id header / gRPC metadata, then assert.
          }
      }
      ```
    </CodeGroup>

    Run the test with your usual runner (`pytest`, `vitest`, `go test`, `./gradlew test`). The override applies only inside this test's session — every other caller still gets the real result.
  </Step>
</Steps>

## What just happened

* The **VPoint** made `pricing/calculate` interceptable without changing its behavior — see [VPoints](/concepts/vpoints).
* The **CEL stage** `42.0` replaced the return value for one **session** — see [Stages](/concepts/stages) and [Sessions](/concepts/sessions).
* `await_sync_or_fail` blocked until the service confirmed it received the stage — see [How tests work](/testing/overview).

## Next steps

<Columns cols={2}>
  <Card title="Instrument a real service" href="/guides/instrument-a-service">
    Class methods, gRPC handlers, service registration, schemas.
  </Card>

  <Card title="Set up session propagation" href="/guides/propagate-sessions">
    One-time setup so the session ID flows through your whole service graph.
  </Card>

  <Card title="Override and observe" href="/guides/override-and-observe">
    Conditional overrides, failure injection, and capturing samples.
  </Card>

  <Card title="Test across services" href="/guides/test-across-services">
    Multi-service flows, mixed-language harnesses.
  </Card>
</Columns>
