Configuration
The CLI reads a JSON config file that defines named profiles —
each profile binds a chain, an RPC URL, and (optionally) a signer.
The merged config feeds every apyx repl and every per-method
subcommand.
{
"defaultProfile": "default",
"profiles": {
"default": {
"chain": "ethereum",
"rpcUrl": "https://eth.llamarpc.com",
"signer": { "type": "key", "keyPath": "~/.apyx/keys/default" }
}
}
}
Schema
type ApyxConfig = {
defaultProfile?: string;
profiles: Record<string, Profile>;
};
type Profile = {
chain: 'ethereum' | 'base';
rpcUrl: string;
signer?: Signer;
};
type Signer =
| { type: 'key'; keyPath: string }
| { type: 'ledger'; derivationPath: string };
| Field | Required | Notes |
|---|---|---|
defaultProfile | no | Name of the profile to use when no --profile flag is passed. Must match a key in profiles. |
profiles | yes | At least one entry — apyx config init creates default. |
profile.chain | yes | "ethereum" or "base". Drives chainId-based address lookup in APYX_ADDRESSES. |
profile.rpcUrl | yes | Non-empty string. Public endpoints work for reads; for writes/heavy reads use a paid RPC. |
profile.signer | no | When omitted, the profile is read-only — apyx repl boots without an account, and writes throw WalletClientRequiredError. |
signer.type = "key" | — | Local-key signing. keyPath points at a hex private-key file. The key itself is never written to the config. |
signer.type = "ledger" | — | Hardware-wallet signing via @ledgerhq/hw-app-eth. derivationPath is the BIP-32 path, e.g. "m/44'/60'/0'/0/0". See Ledger Setup. |
The full validator (with exact error messages) lives in
src/cli/config.ts.
Resolution rules
flowchart LR
A[CLI invocation] --> B{cwd has<br/>./apyx.config.json?}
B -->|yes| C[parse project config]
B -->|no| D[skip project]
C --> E{home config<br/>exists?}
D --> E
E -->|yes| F[parse ~/.apyx/config.json<br/>or $XDG_CONFIG_HOME/apyx/config.json]
E -->|no| G[skip home]
F --> H[merge: project profiles<br/>fully replace home profiles<br/>of the same name]
G --> H
H --> I[resolve profile name<br/>via --profile or defaultProfile]
I --> J[hand to createApyxClient]
| Step | Detail |
|---|---|
| Project config | ./apyx.config.json in the current working directory. |
| Home config | ~/.apyx/config.json, or $XDG_CONFIG_HOME/apyx/config.json when $XDG_CONFIG_HOME is set and non-empty. |
| Merge | Project profiles fully replace home profiles of the same name (no deep merge — a project’s default swap wholly overrides the home’s default, so you can’t accidentally inherit a stale signer block). |
defaultProfile | Project defaultProfile wins if set; else home’s; else the first profile in iteration order. |
| No config anywhere | Most subcommands exit 1 with No config found. Run \apyx config init`. The –versionand–help` flags work without a config. |
Key files (for signer.type = "key")
The config holds a path to a key file, not the key itself.
mkdir -p ~/.apyx/keys
$EDITOR ~/.apyx/keys/default # paste a 32-byte hex key, optional 0x prefix
chmod 600 ~/.apyx/keys/default
| Rule | Effect |
|---|---|
| First non-empty line is read | Trailing comments / mnemonics on later lines are ignored, but cleaner files are easier to audit — keep them one-line. |
0x prefix is optional | Both 0xabcd… and abcd… are accepted. |
| Must decode to exactly 32 bytes | Otherwise: key file does not contain hex / expected 32 bytes (64 hex chars). |
| Permissions are checked | If the file is group- or world-readable, the CLI prints a non-fatal warning suggesting chmod 600 <path>. The key still loads. |
Never put apyx.config.json into a public repo if its keyPath
points at anything sensitive. The recommended pattern: keep
~/.apyx/keys/ outside the repo, and gitignore project-level configs
that reference paths under it.
Inspecting a resolved config
The three apyx config subcommands tell you what the CLI sees:
| Subcommand | Page |
|---|---|
apyx config init | config init |
apyx config show | config show |
apyx config path | config path |
Next
- REPL — what happens when you run
apyx replwith a resolved config. - Session-Start Flags — overriding individual fields per-session without rewriting the config.
- Ledger Setup — adding a
signer.type = "ledger"profile.