Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/rjdellecese/confect/llms.txt

Use this file to discover all available pages before exploring further.

Confect provides type-safe access to environment variables using Effect’s Config API. Environment variables are available in all function types and integrate seamlessly with Convex’s deployment system.

Overview

Type-Safe

Define schemas for environment variables

Effect Config

Use Effect’s Config API for validation

Convex Integration

Works with Convex environment variables

Default Values

Provide fallbacks for optional variables

Accessing Environment Variables

Use Effect’s Config API to access environment variables:
import { Config, Effect } from "effect";

const getAPIKey = Effect.gen(function* () {
  const apiKey = yield* Config.string("API_KEY");
  
  return apiKey;
});
Environment variables are accessed through process.env in Convex, just like in Node.js.

Config Types

Effect provides typed config accessors:

String Config

import { Config } from "effect";

const getDatabaseUrl = Effect.gen(function* () {
  const url = yield* Config.string("DATABASE_URL");
  return url;
});

Number Config

const getPort = Effect.gen(function* () {
  const port = yield* Config.number("PORT");
  return port;
});

Boolean Config

const isProduction = Effect.gen(function* () {
  const prod = yield* Config.boolean("IS_PRODUCTION");
  return prod;
});

Optional Config

const getOptionalKey = Effect.gen(function* () {
  const key = yield* Config.option(Config.string("OPTIONAL_KEY"));
  
  if (Option.isSome(key)) {
    console.log("Key found:", key.value);
  } else {
    console.log("Key not set");
  }
});

Config with Default

const getTimeout = Effect.gen(function* () {
  const timeout = yield* Config.withDefault(
    Config.number("TIMEOUT_MS"),
    5000
  );
  
  return timeout;
});

Setting Environment Variables

Set environment variables in your Convex deployment:
# Development
npx convex env set API_KEY "your-api-key"

# Production
npx convex env set --prod API_KEY "your-prod-api-key"
Environment variables are encrypted at rest and in transit by Convex.

Using in Functions

Access environment variables in your Confect functions:
confect/external.ts
import { FunctionImpl } from "@confect/server";
import { Effect, Config } from "effect";

const callExternalAPI = FunctionImpl.make(
  api,
  "external",
  "fetch",
  ({ endpoint }) =>
    Effect.gen(function* () {
      // Get API key from environment
      const apiKey = yield* Config.string("EXTERNAL_API_KEY");
      
      const response = yield* Effect.tryPromise(() =>
        fetch(`https://api.example.com/${endpoint}`, {
          headers: {
            "Authorization": `Bearer ${apiKey}`,
          },
        })
      );
      
      const data = yield* Effect.tryPromise(() => response.json());
      
      return data;
    }).pipe(Effect.orDie)
);

Structured Configuration

Create structured configuration objects:
config.ts
import { Config, Effect, Schema } from "effect";

const DatabaseConfig = Schema.Struct({
  host: Schema.String,
  port: Schema.Number,
  database: Schema.String,
  user: Schema.String,
  password: Schema.String,
});

const getDatabaseConfig = Effect.gen(function* () {
  const host = yield* Config.string("DB_HOST");
  const port = yield* Config.number("DB_PORT");
  const database = yield* Config.string("DB_NAME");
  const user = yield* Config.string("DB_USER");
  const password = yield* Config.string("DB_PASSWORD");
  
  return {
    host,
    port,
    database,
    user,
    password,
  };
});

Config Validation

Validate environment variables:
import { Config, Effect, Schema } from "effect";

const getEmailConfig = Effect.gen(function* () {
  const apiKey = yield* Config.string("EMAIL_API_KEY");
  
  // Validate API key format
  const validated = yield* Schema.decode(
    Schema.String.pipe(Schema.minLength(32)),
    apiKey
  );
  
  return validated;
});

Environment-Specific Config

const getEnvironment = Effect.gen(function* () {
  const env = yield* Config.withDefault(
    Config.string("ENVIRONMENT"),
    "development"
  );
  
  return env;
});

const getAPIUrl = Effect.gen(function* () {
  const env = yield* getEnvironment;
  
  const url = env === "production"
    ? yield* Config.string("PROD_API_URL")
    : yield* Config.string("DEV_API_URL");
  
  return url;
});

Common Patterns

API Keys

const callThirdPartyAPI = FunctionImpl.make(
  api,
  "integrations",
  "call",
  ({ data }) =>
    Effect.gen(function* () {
      const apiKey = yield* Config.string("THIRD_PARTY_API_KEY");
      
      const response = yield* Effect.tryPromise(() =>
        fetch("https://api.thirdparty.com/endpoint", {
          method: "POST",
          headers: {
            "Authorization": `Bearer ${apiKey}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify(data),
        })
      );
      
      return yield* Effect.tryPromise(() => response.json());
    }).pipe(Effect.orDie)
);

Database Connections

const connectToExternalDB = Effect.gen(function* () {
  const host = yield* Config.string("POSTGRES_HOST");
  const port = yield* Config.number("POSTGRES_PORT");
  const database = yield* Config.string("POSTGRES_DB");
  const user = yield* Config.string("POSTGRES_USER");
  const password = yield* Config.string("POSTGRES_PASSWORD");
  
  const pool = new Pool({
    host,
    port,
    database,
    user,
    password,
  });
  
  return pool;
});

Feature Flags

const isFeatureEnabled = (feature: string) =>
  Effect.gen(function* () {
    const enabled = yield* Config.withDefault(
      Config.boolean(`FEATURE_${feature.toUpperCase()}_ENABLED`),
      false
    );
    
    return enabled;
  });

const processData = FunctionImpl.make(
  api,
  "data",
  "process",
  ({ data }) =>
    Effect.gen(function* () {
      const useNewAlgorithm = yield* isFeatureEnabled("new_algorithm");
      
      if (useNewAlgorithm) {
        return yield* processWithNewAlgorithm(data);
      } else {
        return yield* processWithOldAlgorithm(data);
      }
    }).pipe(Effect.orDie)
);

Error Handling

Handle missing environment variables:
const getAPIKeyWithFallback = Effect.gen(function* () {
  const apiKey = yield* Config.string("API_KEY").pipe(
    Effect.catchAll(() =>
      Effect.gen(function* () {
        console.warn("API_KEY not set, using demo key");
        return "demo-api-key";
      })
    )
  );
  
  return apiKey;
});

Secrets Management

Never commit environment variables containing secrets to version control. Use Convex’s environment variable management instead.
# Set secrets via CLI
npx convex env set SECRET_KEY "your-secret"

# List environment variables (values are hidden)
npx convex env list

# Remove environment variable
npx convex env unset SECRET_KEY

Configuration Service

Create a reusable configuration service:
services/config.ts
import { Config, Effect, Context, Layer } from "effect";

interface AppConfig {
  readonly apiKey: string;
  readonly apiUrl: string;
  readonly timeout: number;
  readonly debug: boolean;
}

class AppConfig extends Context.Tag("AppConfig")<
  AppConfig,
  AppConfig
>() {}

const makeAppConfig = Effect.gen(function* () {
  const apiKey = yield* Config.string("API_KEY");
  const apiUrl = yield* Config.withDefault(
    Config.string("API_URL"),
    "https://api.example.com"
  );
  const timeout = yield* Config.withDefault(
    Config.number("TIMEOUT_MS"),
    5000
  );
  const debug = yield* Config.withDefault(
    Config.boolean("DEBUG"),
    false
  );
  
  return {
    apiKey,
    apiUrl,
    timeout,
    debug,
  };
});

export const AppConfigLive = Layer.effect(AppConfig, makeAppConfig);

// Usage
const useConfig = Effect.gen(function* () {
  const config = yield* AppConfig;
  
  console.log("API URL:", config.apiUrl);
  console.log("Timeout:", config.timeout);
});

Best Practices

1

Use Type-Safe Config

Always use Effect’s Config API instead of accessing process.env directly.
2

Provide Defaults

Use Config.withDefault for non-critical configuration.
3

Validate Early

Validate configuration at application startup, not at runtime.
4

Document Requirements

Document all required environment variables in your README.
Confect automatically provides a ConvexConfigProvider that reads from process.env. You don’t need to configure it manually.

Testing with Environment Variables

Mock environment variables in tests:
import { ConfigProvider, Effect, Layer } from "effect";

const testConfig = ConfigProvider.fromMap(
  new Map([
    ["API_KEY", "test-api-key"],
    ["API_URL", "http://localhost:3000"],
    ["DEBUG", "true"],
  ])
);

const testLayer = Layer.setConfigProvider(testConfig);

// Use in tests
const testEffect = Effect.gen(function* () {
  const apiKey = yield* Config.string("API_KEY");
  expect(apiKey).toBe("test-api-key");
}).pipe(Effect.provide(testLayer));

Next Steps

Functions

Use config in your functions

Node Actions

Access environment in Node actions

HTTP API

Configure HTTP endpoints

Effect Config

Learn more about Effect Config