Project Structure TL;DR

Your project is just a directory with a dfx.json file that points to your .ts or .js entrypoint.

Here's what your directory structure might look like:

hello_world/
|
├── dfx.json
|
└── src/
    └── api.ts

For an HTTP Server canister this would be the simplest corresponding dfx.json file:

{
    "canisters": {
        "api": {
            "type": "azle",
            "main": "src/api.ts",
            "custom": {
                "experimental": true,
                "candid_gen": "http"
            }
        }
    }
}

For a Candid RPC canister this would be the simplest corresponding dfx.json file:

{
    "canisters": {
        "api": {
            "type": "azle",
            "main": "src/api.ts"
        }
    }
}

Once you have created this directory structure you can deploy to mainnet or a locally running replica by running the dfx deploy command in the same directory as your dfx.json file.

dfx.json

The dfx.json file is the main ICP-specific configuration file for your canisters. The following are various examples of dfx.json files.

Automatic Candid File Generation

The command-line tools dfx require a Candid file to deploy your canister. Candid RPC canisters will automatically have their Candid files generated and stored in the .azle directory without any extra property in the dfx.json file. HTTP Server canisters must specify "candid_gen": "http" for their Candid files to be generated automatically in the .azle directory:

{
    "canisters": {
        "api": {
            "type": "azle",
            "main": "src/api.ts",
            "custom": {
                "experimental": true,
                "candid_gen": "http"
            }
        }
    }
}

Custom Candid File

If you would like to provide your own custom Candid file you can specify "candid": "[path to your candid file]" and "candid_gen": "custom":

{
    "canisters": {
        "api": {
            "type": "azle",
            "main": "src/api.ts",
            "candid": "src/api.did",
            "custom": {
                "experimental": true,
                "candid_gen": "custom"
            }
        }
    }
}

Environment Variables

You can provide environment variables to Azle canisters by specifying their names in your dfx.json file and then accessing them through the process.env object in Azle.

You must provide the environment variables that you want included in the same process as your dfx deploy command.

Be aware that the environment variables that you specify in your dfx.json file will be included in plain text in your canister's Wasm binary.

{
    "canisters": {
        "api": {
            "type": "azle",
            "main": "src/api.ts",
            "custom": {
                "experimental": true,
                "candid_gen": "http",
                "env": ["MY_ENVIRONMENT_VARIABLE"]
            }
        }
    }
}

Assets

See the Assets chapter for more information:

{
    "canisters": {
        "api": {
            "type": "azle",
            "main": "src/api.ts",
            "custom": {
                "experimental": true,
                "candid_gen": "http",
                "assets": [
                    ["src/frontend/dist", "dist"],
                    ["src/backend/media/audio.ogg", "media/audio.ogg"],
                    ["src/backend/media/video.ogv", "media/video.ogv"]
                ]
            }
        }
    }
}

Build Assets

See the Assets chapter for more information:

{
    "canisters": {
        "api": {
            "type": "azle",
            "main": "src/api.ts",
            "custom": {
                "experimental": true,
                "candid_gen": "http",
                "assets": [
                    ["src/frontend/dist", "dist"],
                    ["src/backend/media/audio.ogg", "media/audio.ogg"],
                    ["src/backend/media/video.ogv", "media/video.ogv"]
                ],
                "build_assets": "npm run build"
            }
        }
    }
}

ESM Externals

This will instruct Azle's TypeScript/JavaScript build process to ignore bundling the provided named packages.

Sometimes the build process is overly eager to include packages that won't actually be used at runtime. This can be a problem if those packages wouldn't even work at runtime due to limitations in ICP or Azle. It is thus useful to be able to exclude them:

{
    "canisters": {
        "api": {
            "type": "azle",
            "main": "src/api.ts",
            "custom": {
                "experimental": true,
                "candid_gen": "http",
                "esm_externals": ["@nestjs/microservices", "@nestjs/websockets"]
            }
        }
    }
}

ESM Aliases

This will instruct Azle's TypeScript/JavaScript build process to alias a package name to another pacakge name.

This can be useful if you need to polyfill certain packages that might not exist in Azle:

{
    "canisters": {
        "api": {
            "type": "azle",
            "main": "src/api.ts",
            "custom": {
                "experimental": true,
                "candid_gen": "http",
                "esm_aliases": {
                    "crypto": "crypto-browserify"
                }
            }
        }
    }
}