KeyEnvKeyEnv
SDKs & Integrations

Deno

Using KeyEnv with Deno applications.

Deno Integration

Load KeyEnv secrets in your Deno applications using the CLI or direct API calls.

The simplest way to use KeyEnv with Deno is via the CLI's run command.

Install the CLI

curl -fsSL https://keyenv.dev/install.sh | bash

Configure deno.json

{
  "tasks": {
    "dev": "keyenv run -p YOUR_PROJECT_ID -e development -- deno run -A src/main.ts",
    "start": "keyenv run -p YOUR_PROJECT_ID -e production -- deno run -A src/main.ts"
  }
}

Run with Secrets

# Set your token
export KEYENV_TOKEN=your-service-token

# Run with secrets injected
deno task dev

Direct API Usage

Deno has built-in fetch, so you can call the KeyEnv API directly without any dependencies.

Fetch and Load Secrets

const KEYENV_TOKEN = Deno.env.get("KEYENV_TOKEN");
const PROJECT_ID = "your-project-id";
const ENVIRONMENT = "production";

interface Secret {
  key: string;
  value: string;
}

interface ExportResponse {
  data: Secret[];
}

async function loadSecrets(): Promise<void> {
  const response = await fetch(
    `https://api.keyenv.dev/api/v1/projects/${PROJECT_ID}/environments/${ENVIRONMENT}/secrets/export`,
    {
      headers: {
        "Authorization": `Bearer ${KEYENV_TOKEN}`,
        "Content-Type": "application/json",
      },
    }
  );

  if (!response.ok) {
    throw new Error(`Failed to fetch secrets: ${response.status}`);
  }

  const data: ExportResponse = await response.json();

  for (const secret of data.secrets) {
    Deno.env.set(secret.key, secret.value);
  }

  console.log(`Loaded ${data.secrets.length} secrets`);
}

// Load at startup
await loadSecrets();

// Use secrets
console.log(Deno.env.get("DATABASE_URL"));

Create a Reusable Module

// keyenv.ts
const API_BASE = "https://api.keyenv.dev/api/v1";

export interface KeyEnvConfig {
  token: string;
  projectId: string;
  environment: string;
}

export interface Secret {
  key: string;
  value: string;
  description?: string;
}

export class KeyEnv {
  private token: string;
  private projectId: string;
  private environment: string;

  constructor(config: KeyEnvConfig) {
    this.token = config.token;
    this.projectId = config.projectId;
    this.environment = config.environment;
  }

  private async fetch<T>(path: string, options?: RequestInit): Promise<T> {
    const response = await fetch(`${API_BASE}${path}`, {
      ...options,
      headers: {
        "Authorization": `Bearer ${this.token}`,
        "Content-Type": "application/json",
        ...options?.headers,
      },
    });

    if (!response.ok) {
      const error = await response.json().catch(() => ({}));
      throw new Error(error.message || `HTTP ${response.status}`);
    }

    return response.json();
  }

  async exportSecrets(): Promise<Secret[]> {
    const data = await this.fetch<{ data: Secret[] }>(
      `/projects/${this.projectId}/environments/${this.environment}/secrets/export`
    );
    return data.data;
  }

  async loadEnv(): Promise<number> {
    const secrets = await this.exportSecrets();
    for (const secret of secrets) {
      Deno.env.set(secret.key, secret.value);
    }
    return secrets.length;
  }

  async getSecret(key: string): Promise<Secret> {
    return this.fetch<Secret>(
      `/projects/${this.projectId}/environments/${this.environment}/secrets/${key}`
    );
  }

  async setSecret(key: string, value: string, description?: string): Promise<void> {
    await this.fetch(
      `/projects/${this.projectId}/environments/${this.environment}/secrets/${key}`,
      {
        method: "PUT",
        body: JSON.stringify({ value, description }),
      }
    );
  }
}

Using the Module

// main.ts
import { KeyEnv } from "./keyenv.ts";

const keyenv = new KeyEnv({
  token: Deno.env.get("KEYENV_TOKEN")!,
  projectId: "your-project-id",
  environment: "production",
});

// Load all secrets into environment
await keyenv.loadEnv();

// Or get specific secrets
const dbUrl = await keyenv.getSecret("DATABASE_URL");
console.log(dbUrl.value);

Deno Deploy

For Deno Deploy, use environment variables or the direct API approach.

Using Environment Variables

Set KEYENV_TOKEN in your Deno Deploy project settings, then fetch secrets at startup:

// main.ts
const TOKEN = Deno.env.get("KEYENV_TOKEN");
const PROJECT = Deno.env.get("KEYENV_PROJECT");

// Cache secrets in module scope
let secrets: Map<string, string> | null = null;

async function getSecrets(): Promise<Map<string, string>> {
  if (secrets) return secrets;

  const response = await fetch(
    `https://api.keyenv.dev/api/v1/projects/${PROJECT}/environments/production/secrets/export`,
    { headers: { "Authorization": `Bearer ${TOKEN}` } }
  );

  const data = await response.json();
  secrets = new Map(data.secrets.map((s: any) => [s.key, s.value]));
  return secrets;
}

Deno.serve(async (_req) => {
  const env = await getSecrets();
  // Use env.get("DATABASE_URL"), etc.
  return new Response("OK");
});

Fresh Framework

For Fresh applications, load secrets in a plugin or middleware:

// plugins/keyenv.ts
import { Plugin } from "$fresh/server.ts";

const TOKEN = Deno.env.get("KEYENV_TOKEN");
const PROJECT = Deno.env.get("KEYENV_PROJECT");

export default {
  name: "keyenv",
  async configureServer() {
    const response = await fetch(
      `https://api.keyenv.dev/api/v1/projects/${PROJECT}/environments/production/secrets/export`,
      { headers: { "Authorization": `Bearer ${TOKEN}` } }
    );

    const data = await response.json();
    for (const secret of data.secrets) {
      Deno.env.set(secret.key, secret.value);
    }

    console.log(`Loaded ${data.secrets.length} secrets from KeyEnv`);
  },
} satisfies Plugin;

Best Practices

  1. Use the CLI for local development - It handles token management and environment switching.

  2. Cache secrets in production - Avoid fetching on every request:

    let cachedSecrets: Map<string, string> | null = null;
    let cacheExpiry = 0;
    
    async function getSecrets() {
      if (cachedSecrets && Date.now() < cacheExpiry) {
        return cachedSecrets;
      }
      // Fetch and cache for 5 minutes
      cachedSecrets = await fetchSecrets();
      cacheExpiry = Date.now() + 5 * 60 * 1000;
      return cachedSecrets;
    }
  3. Handle errors gracefully:

    try {
      await loadSecrets();
    } catch (error) {
      console.error("Failed to load secrets:", error);
      Deno.exit(1);
    }
  4. Don't commit tokens - Use environment variables or a .env file (gitignored).

On this page