SDKs & Integrations
Deno
Using KeyEnv with Deno applications.
Deno Integration
Load KeyEnv secrets in your Deno applications using the CLI or direct API calls.
Using the CLI (Recommended)
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 | bashConfigure 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 devDirect 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
-
Use the CLI for local development - It handles token management and environment switching.
-
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; } -
Handle errors gracefully:
try { await loadSecrets(); } catch (error) { console.error("Failed to load secrets:", error); Deno.exit(1); } -
Don't commit tokens - Use environment variables or a
.envfile (gitignored).