Your First Full Project
This tutorial takes you from an empty folder to a contract deployed on a local network and called from TypeScript. You create a Counter contract with aztec init, compile it, generate its TypeScript bindings, and write one script that deploys it, increments it and reads it back.
Prerequisites
- Node.js (v24.15.0 or later) and npm
- The Aztec CLI at version 6.0.0, with a local network running. See Getting started on the local network to install the CLI and start the network with
aztec start --local-network.
Create the contract
Create an empty folder and initialize an Aztec project in it:
mkdir my_project
cd my_project
aztec init
aztec init names the project after the folder. It creates a workspace with two crates:
my_project_contract/: aCountercontract that keeps a private counter per ownermy_project_test/: Noir tests for the contract, which you run withaztec test
Compile the contract and generate its TypeScript bindings:
aztec compile
aztec codegen target -o src/artifacts
aztec compile writes the contract artifact to target/my_project_contract-Counter.json. aztec codegen turns it into src/artifacts/Counter.ts, which exports a typed CounterContract class.
Set up the TypeScript project
Create these two files in my_project/. The Aztec packages must match your CLI version.
{
"name": "my-project",
"private": true,
"type": "module",
"scripts": {
"start": "tsx src/index.ts",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@aztec-labs/accounts": "6.0.0",
"@aztec-labs/aztec.js": "6.0.0",
"@aztec-labs/wallets": "6.0.0"
},
"devDependencies": {
"@types/node": "22.20.5",
"tsx": "4.23.15",
"typescript": "5.9.3"
}
}
{
"compilerOptions": {
"target": "es2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"noEmit": true
},
"include": ["src/**/*.ts"]
}
Install the dependencies:
npm install
Write the script
Create src/index.ts:
import { getInitialTestAccountsData } from "@aztec-labs/accounts/testing";
import { EmbeddedWallet } from "@aztec-labs/wallets/embedded";
import { CounterContract } from "./artifacts/Counter.js";
const nodeUrl = process.env.AZTEC_NODE_URL ?? "http://localhost:8080";
const wallet = await EmbeddedWallet.create(nodeUrl, { ephemeral: true });
// The local network funds its test accounts, so they pay fees without being deployed first.
const [aliceData] = await getInitialTestAccountsData();
const alice = await wallet.createSchnorrInitializerlessAccount(
aliceData.secret,
aliceData.salt,
aliceData.signingKey,
);
const { contract: counter } = await CounterContract.deploy(
wallet,
10,
alice.address,
).send({ from: alice.address });
console.log(`Counter deployed at ${counter.address}`);
await counter.methods.increment(alice.address).send({ from: alice.address });
const { result: value } = await counter.methods
.get_counter(alice.address)
.simulate({ from: alice.address });
console.log(`Counter value: ${value}`);
Source code: docs/lines/v6/examples/ts/first_full_project/index.ts#L1-L30
The script:
- Creates an
EmbeddedWallet, which runs a PXE (Private eXecution Environment) inside the script.ephemeral: truekeeps its state in memory only. - Adds the first of the local network's test accounts. The network funds them at genesis, so they pay fees without being deployed first.
- Deploys the Counter with an initial value of 10, owned by that account. The constructor is a private function, so it runs in the PXE before the transaction is sent.
- Calls
increment, a private function, and then reads the counter withget_counter, a utility function that runs in the PXE without a transaction.
Run it
npm start
Expected output (your address differs):
Counter deployed at 0x...
Counter value: 11
Your project now has everything a larger app needs: a contract workspace with tests, generated bindings, and a TypeScript client.
Troubleshooting
- The import of
./artifacts/Counter.jsfails: runaztec codegen target -o src/artifactsafter everyaztec compile. - The script cannot reach the node: start the local network with
aztec start --local-network. The script connects tohttp://localhost:8080unless you setAZTEC_NODE_URL. - Errors after you upgrade the CLI: the
@aztec-labs/*versions inpackage.jsonmust equal the versionaztec --versionprints.
Next steps
- Counter contract explains the contract line by line.
- Testing contracts covers the tests in
my_project_test/. - Deploying a token contract uses a prebuilt token contract and private transfers.