A type-safe, reusable environment configuration abstraction for Dagger modules.
npm install dagger-envA type-safe, reusable environment configuration abstraction for Dagger modules with full Zod v4 validation and 1Password integration.
- 🔒 Type-safe: Full TypeScript support with Zod v4 validation
- 🔄 Reusable: Create multiple environment configurations for different projects
- 🎯 Consistent: Standardized API across all Dagger modules
- 🛡️ Validated: Runtime validation of arguments, environment variables, and secrets
- 📦 Modular: Secret presets and derived environment variables
- 🔐 1Password Integration: Built-in command runner with op run support
- 🚀 Easy to use: Simple configuration-based setup
``bash`
npm install dagger-env zod
Note: The command runner functionality (dagger-env/run) requires the 1Password CLI (op) to be installed.
`typescript
import { createDaggerEnv } from 'dagger-env'
import { z } from 'zod/v4'
// Define your environment configuration
const myDaggerEnv = createDaggerEnv({
args: z.object({
push: z.string().optional(),
environment: z.enum(['dev', 'staging', 'prod']).optional()
}),
env: z.object({
CI: z.string().optional(),
NODE_ENV: z.string().optional()
}),
secrets: z.object({
API_TOKEN: z.string(),
DATABASE_URL: z.string(),
REDIS_URL: z.string()
}),
secretPresets: {
api: ['API_TOKEN', 'DATABASE_URL'],
cache: ['REDIS_URL']
},
derivedEnvVars: {
API_TOKEN: {
API_BASE_URL: 'https://api.example.com',
API_VERSION: 'v1'
},
DATABASE_URL: {
DB_POOL_SIZE: '10'
}
}
})
`
`typescript
// Use in your Dagger module
import { Container, dag, func, object, Secret } from '@dagger.io/dagger'
@object()
export class MyModule {
@func()
async build(options: Secret): Promise
const opts = await myDaggerEnv.parseDaggerOptions(options)
const { withEnv } = await myDaggerEnv.getWithEnv(options, ['api'], ['REDIS_URL'])
return withEnv(dag.container().from('node:18')).withExec(['npm', 'run', 'build']).sync()
}
}
`
For projects using 1Password for secret management, dagger-env provides a convenient command runner that integrates with op run:
`typescript
import { createDaggerEnv } from 'dagger-env'
import { createDaggerCommandRunner } from 'dagger-env/run'
import { z } from 'zod/v4'
// Create your DaggerEnv configuration
const myDaggerEnv = createDaggerEnv({
args: z.object({
environment: z.enum(['dev', 'staging', 'prod']).optional()
}),
env: z.object({
CI: z.string().optional(),
NODE_ENV: z.string().optional()
}),
secrets: z.object({
API_TOKEN: z.string()
}),
secretPresets: {
api: ['API_TOKEN']
},
derivedEnvVars: {}
})
// Create a command runner - simply pass your DaggerEnv instance
const runDaggerCommand = createDaggerCommandRunner({
opVault: 'your-vault-id',
opItem: 'your-item-id',
opSections: [
{
id: 'your-section-id',
label: 'Shared'
}
],
dockerCommands: ['build', 'deploy', 'test'],
daggerEnv: myDaggerEnv
})
// Run a Dagger command
await runDaggerCommand('test', {
args: { environment: 'dev' },
env: { NODE_ENV: 'development' }
})
`
`typescript`
// Advanced configuration with multiple sections and pre-command setup
const runDaggerCommand = createDaggerCommandRunner({
opVault: 'your-vault-id',
opItem: 'your-item-id',
opSections: [
{ id: 'shared-section-id', label: 'Shared' },
{ id: 'project-section-id', label: 'Project Specific' }
],
dockerCommands: ['build', 'deploy', 'test'],
beforeCommand: async () => {
// Setup vendor files, modules, etc.
console.log('Setting up environment...')
// await setupDaggerVendorFiles()
},
daggerEnv: myDaggerEnv
})
#### createDaggerEnv(config)
Creates a new DaggerEnv instance with the provided configuration.
Parameters:
- config.args: Zod schema for command-line argumentsconfig.env
- : Zod schema for environment variablesconfig.secrets
- : Zod schema for secretsconfig.secretPresets
- : Object mapping preset names to arrays of secret namesconfig.derivedEnvVars
- : Object mapping secret names to derived environment variables
Returns: DaggerEnv instance
Parses and validates dagger options from a Secret containing JSON.
Parameters:
- options: Dagger Secret containing JSON options
Returns: Promise - Parsed and typed options object
Creates a function that applies environment variables and secrets to a container.
Parameters:
- options: Secret or parsed options objectsecretPresets
- : Array of preset names to include (e.g., ['api', 'cache'])secretNames
- : Optional array of additional individual secret names
Returns: Promise<(con: Container) => Container> - Function that applies env vars and secrets
Returns the Zod schema for the complete options object. Primarily used internally by the command runner, but available for advanced use cases.
Returns: ZodObject - The combined schema for args, env, and secrets
Returns array of available secret preset names.
Returns: Array - Available preset names
Returns array of secret names for a specific preset.
Parameters:
- preset: Name of the preset
Returns: readonly string[] - Secret names in the preset
#### createDaggerCommandRunner(config)
Creates a function to run Dagger commands with 1Password integration.
Parameters:
- config.opVault: 1Password vault IDconfig.opItem
- : 1Password item IDconfig.opSections
- : Array of 1Password sections to include for secretsconfig.dockerCommands
- : Optional array of command names that should include Docker socketconfig.beforeCommand
- : Optional async function to run before executing the commandconfig.daggerEnv
- : DaggerEnv instance for schema validation and type safety
Returns: (commandName: string, options?: RunDaggerCommandOptions) => Promise - Function to execute Dagger commands
#### RunDaggerCommandOptions
Options for individual command execution:
- args: Optional record of arguments to pass to the Dagger commandenv
- : Optional record of additional environment variablesextraArgs
- : Optional array of additional command-line arguments
`typescript`
const apiServiceEnv = createDaggerEnv({
args: z.object({
push: z.string().optional()
}),
env: z.object({
CI: z.string().optional()
}),
secrets: z.object({
API_TOKEN: z.string(),
DATABASE_URL: z.string()
}),
secretPresets: {
api: ['API_TOKEN', 'DATABASE_URL']
} as const,
derivedEnvVars: {
API_TOKEN: {
API_BASE_URL: 'https://api.example.com'
}
} as const
})
`typescript`
const multiEnvDaggerEnv = createDaggerEnv({
args: z.object({
environment: z.enum(['dev', 'staging', 'prod']),
push: z.string().optional()
}),
env: z.object({
CI: z.string().optional()
}),
secrets: z.object({
DEV_API_KEY: z.string(),
STAGING_API_KEY: z.string(),
PROD_API_KEY: z.string()
}),
secretPresets: {
dev: ['DEV_API_KEY'],
staging: ['STAGING_API_KEY'],
prod: ['PROD_API_KEY']
} as const,
derivedEnvVars: {
DEV_API_KEY: { API_URL: 'https://dev-api.example.com' },
STAGING_API_KEY: { API_URL: 'https://staging-api.example.com' },
PROD_API_KEY: { API_URL: 'https://api.example.com' }
} as const
})
For advanced use cases where you need to extract TypeScript types:
`typescript
import { z } from 'zod/v4'
import type { DaggerOptionsFromConfig } from 'dagger-env'
// Extract the options type from your DaggerEnv configuration
type MyDaggerEnvConfig = typeof myDaggerEnv extends DaggerEnv
type MyOptions = DaggerOptionsFromConfig
// Access the schema if needed for validation or type extraction
const schema = myDaggerEnv.getOptionsSchema()
type SchemaOutput = z.output
`
1. Use as const for secretPresets and derivedEnvVars to ensure proper typingapi
2. Group related secrets into logical presets (e.g., , database, cache)parseDaggerOptions()` at the start of functions
3. Validate early by calling
4. Reuse configurations across multiple Dagger modules in the same project
5. Document your schemas with JSDoc comments for better developer experience
- Node.js 18+
- Dagger SDK
- Zod v4+
MIT
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.