Getting Started
Let's be honest - most configuration tools make you write a novel before you can generate a single file. Not here. You can start with just a few lines and grow from there.
The Absolute Minimum
Create an axogen.config.ts file:
import {defineConfig, env} from "@axonotes/axogen";
export default defineConfig({
targets: {
app: env({
path: "app/.env",
variables: {
NODE_ENV: "development",
PORT: 3000,
},
}),
},
});
Run it:
axogen generate
Boom. You've got an app/.env file. Not earth-shattering, but you're up and
running.

Adding Environment Variables
Of course, hardcoded values aren't very useful. Let's make it read from your actual environment:
import {defineConfig, env, loadEnv} from "@axonotes/axogen";
import * as z from "zod";
const envVars = loadEnv(
z.object({
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string(),
})
);
export default defineConfig({
targets: {
app: env({
path: "app/.env",
variables: {
PORT: envVars.PORT,
DATABASE_URL: envVars.DATABASE_URL,
},
}),
},
});
Create a .env.axogen file with your values:
PORT=3000
DATABASE_URL=postgresql://localhost:5432/myapp
Add .env.axogen to your .gitignore file! It's just like any other .env
file - you don't want to push your secrets to git.
Now when you run axogen generate, it validates your environment variables and
generates the config. If DATABASE_URL is missing, it'll yell at you. No more
silent failures.

Multiple Formats
Here's where it gets interesting. Need the same data in different formats? Easy:
import {defineConfig, env, json, loadEnv} from "@axonotes/axogen";
import * as z from "zod";
const envVars = loadEnv(
z.object({
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string(),
})
);
export default defineConfig({
targets: {
app: env({
path: "app/.env",
variables: {
PORT: envVars.PORT,
DATABASE_URL: envVars.DATABASE_URL,
},
}),
config: json({
path: "config.json",
variables: {
database: {
url: envVars.DATABASE_URL,
},
server: {
port: envVars.PORT,
},
},
}),
},
});
One source of truth, multiple outputs. Your backend reads the .env, your
frontend build process reads the JSON. They're always in sync.
Adding Commands
Sometimes you want to run things after generating configs:
export default defineConfig({
targets: {
// ... your targets
},
commands: {
start: "npm start",
dev: "npm run dev",
},
});
axogen run start
CLI Reference
# Generate all targets
axogen generate
# Generate specific target
axogen generate --target app
# See what would be generated (without writing files)
axogen generate --dry-run
# Run commands
axogen run start
# Get help on any command
axogen run --help
axogen generate --help
What's Next?
This is the foundation. Start small, grow as needed. Check out:
- Basic Configuration - Core concepts and patterns
- Target Types - All the file formats you can generate
- Commands System - Task management and automation
Configuration management doesn't have to suck. Your environment variables can have types. Your scripts can be intelligent. Your deployments can be consistent.
That's the way.