Skip to content

Configuration

dap.config.js is the single source of truth for DappQL codegen, which contracts to emit, where to put them, what flags to set, what MCP gates to open. This page is the full field reference.

Minimal config

js
export default {
  targetPath: './src/contracts',
  contracts: {
    Token: { address: '0x...', abi: [/* ... */] },
  },
}

Run npx dappql and you get ./src/contracts/Token.ts plus ./src/contracts/index.ts.

Full field reference

ts
type Config = {
  // Required
  contracts: Record<string, ContractConfig>
  targetPath: string

  // Codegen behavior
  isModule?: boolean
  isSdk?: boolean
  agentsFile?: boolean | string

  // ABI fetching
  abiSourcePath?: string
  etherscanApiKey?: string
  etherscanApi?: string
  chainId?: number

  // @dappql/mcp
  mcp?: {
    rpc?: string
    allowWrites?: boolean
    allowCodegen?: boolean
  }
}

type ContractConfig = {
  address?: `0x${string}`
  abi?: AbiItem[]
  isTemplate?: boolean
}

contracts (required)

A map of contract names to { address, abi, isTemplate }. The key becomes the module name in generated code (ContractName.ts), the namespace import in your app, and the resolver key for addressResolver.

js
contracts: {
  Token: {
    address: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599',
    abi: [/* ABI JSON */],
  },
  USDC: {
    address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
    abi: [/* ABI JSON */],
  },
  // Template, no single canonical address; use .at() per call
  ERC20: {
    isTemplate: true,
    abi: [/* ERC20 ABI */],
  },
}

Per-contract fields:

  • address, the deploy address. Required for singletons. Optional for templates, but useful as a canonical-implementation reference.
  • abi, the full ABI array. If omitted and etherscanApiKey is set, the CLI will fetch it.
  • isTemplate, flag contracts deployed at many addresses. Generated code omits the baked-in deployAddress, and every call requires .at(addr) or an address option on mutations. See Template contracts.

targetPath (required)

Where to write generated contract modules. Relative to the config file's directory. Conventional: './src/contracts'.

The CLI cleans this directory before emitting, so keep it dedicated to generated output, don't mix in hand-written files.

isModule

js
isModule: true  // emits ESM import paths (import from './X.js')
isModule: false // default, omits extensions, matches TS/CJS projects

Set to true for modern ESM projects (your package.json has "type": "module"). For most Next.js/Vite apps, the default is fine.

isSdk

js
isSdk: true

Flip on to additionally emit ${targetPath}/sdk.ts, a createSdk(publicClient, walletClient, addressResolver?) factory that wraps every contract into a single typed object. This is how protocols ship their frontend primitives as publishable SDKs. See SDK generation.

agentsFile

js
agentsFile: true                  // default, write ./AGENTS.md at repo root
agentsFile: false                 // opt out
agentsFile: './docs/AGENTS.md'    // custom location

Controls the per-project AGENTS.md the CLI generates for AI coding agents. See Generated AGENTS.md.

chainId

js
chainId: 8453  // Base mainnet

Used in two places:

  1. Included in the generated AGENTS.md setup section.
  2. Passed to Etherscan when fetching ABIs for contracts that omit them.

Not required if every contract has an abi in config.

abiSourcePath

js
abiSourcePath: './abis'

Load ABIs from local JSON files named ${ContractName}.json. Checked before falling back to Etherscan. Useful when you generate ABIs from Foundry/Hardhat builds.

etherscanApiKey + etherscanApi

js
etherscanApiKey: process.env.ETHERSCAN_API_KEY,
etherscanApi: 'https://api.etherscan.io/v2/api',  // default

If a contract omits abi, the CLI fetches it from Etherscan. Set etherscanApi to override, the v2 API works for Basescan, Arbiscan, and other chain explorers that mirror it.

mcp

Settings for @dappql/mcp:

js
mcp: {
  rpc: 'https://mainnet.base.org',  // overrides DAPPQL_RPC_URL env
  allowWrites: false,               // gate for the callWrite tool
  allowCodegen: false,              // gate for the regenerate tool
}

All optional. rpc is consulted before the env var; allowWrites and allowCodegen default to false. See Safety model.

Typical configurations

React app with embedded ABIs

js
export default {
  targetPath: './src/contracts',
  isModule: true,
  agentsFile: true,
  contracts: {
    Token: { address: '0x...', abi: [/* ... */] },
    ToDo:  { address: '0x...', abi: [/* ... */] },
  },
}

Protocol shipping a publishable SDK

js
export default {
  name: 'My Protocol SDK',
  targetPath: './src/contracts',
  chainId: 8453,
  isModule: true,
  isSdk: true,
  contracts: {
    Factory:    { address: '0x...', abi: [/* ... */] },
    Registry:   { address: '0x...', abi: [/* ... */] },
    UserVault:  { isTemplate: true, abi: [/* ... */] },
    ERC20:      { isTemplate: true, abi: [/* ... */] },
  },
}

Auto-fetched ABIs from Etherscan

js
export default {
  targetPath: './src/contracts',
  chainId: 1,
  etherscanApiKey: process.env.ETHERSCAN_API_KEY,
  contracts: {
    WETH: { address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' },
    USDC: { address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' },
  },
}

ABIs resolve per contract in this order: embedded abi → local JSON at abiSourcePath/ContractName.json → Etherscan.

MCP-ready with gated codegen

js
export default {
  targetPath: './src/contracts',
  isSdk: true,
  contracts: { /* ... */ },
  mcp: {
    rpc: 'https://mainnet.base.org',
    allowCodegen: true,   // lets the MCP regenerate tool run
    // allowWrites left off, safest default
  },
}

Generated output

After npx dappql:

./src/contracts/
  ├── Token.ts           # per-contract: abi, call, mutation, events, deployAddress
  ├── ToDo.ts
  ├── ERC20.ts           # isTemplate: true, no deployAddress, .at() required
  ├── index.ts           # re-exports each contract as a namespace
  └── sdk.ts             # only when isSdk: true

Plus a project-level AGENTS.md (unless agentsFile: false).

File format and extensions

  • dap.config.js, the conventional filename. The CLI also accepts dap.config.mjs and dap.config.cjs.
  • Use export default (ESM) or module.exports = { ... } (CJS) depending on your project.
  • The file is imported at runtime by the CLI; any JavaScript you'd expect works, dynamic construction, env vars, conditional logic.

Dynamic configurations

The config file is just JavaScript, build it programmatically if that fits:

js
import manifest from './manifest.json' with { type: 'json' }

export default {
  targetPath: './src/contracts',
  chainId: manifest.chainId,
  contracts: Object.fromEntries(
    Object.entries(manifest.contracts).map(
      ([name, { address, abi }]) => [name, { address, abi }]
    ),
  ),
}

Perfect for generated manifests (Foundry's out/ directory, a deploy pipeline that spits out addresses, or a cross-chain build that iterates over a list of chains).