Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

The Fuel TypeScript SDK (fuels) — Admin & Architecture Guide

Generated June 2026 from FuelLabs/fuels-ts at b3f37c9

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for the engineers, architects, and contributors who need to understand how fuels-ts is built — its monorepo layout, package dependency graph, the Sway→TypeScript codegen pipeline, the UTXO transaction-assembly engine, the ABI coder, binary management, and the release machinery. For day-to-day SDK usage, see the companion User Guide.

fuels-ts is the official TypeScript SDK for the Fuel network. It is a pnpm + Turborepo monorepo that publishes ~20 scoped @fuel-ts/* packages, an umbrella fuels package (which re-exports them all and carries the CLI), a create-fuels scaffolding tool, and an @fuel-ts/abi-typegen code generator. It is licensed Apache-2.0.


1. Executive Summary

Attribute Value
Project fuels-ts — Fuel TypeScript SDK
Author Fuel Labs
License Apache-2.0
Language TypeScript
Repository git+https://github.com/FuelLabs/fuels-ts.git
Monorepo manager pnpm ^9.4.0 workspaces
Build orchestrator Turborepo (turbo)
Per-package bundler tsup (esbuild) → CJS + ESM + IIFE
Test runner Vitest (node + browser projects) + Playwright
Release tooling Changesets
Node support ^20.0.0 || ^22.0.0 || ^24.0.0
External binaries forc (Sway compiler), fuel-core (node)

What it is. A client SDK that lets TypeScript applications create wallets, deploy and call Sway programs (contracts, scripts, predicates), and build/submit transactions on a UTXO-based chain. Conceptually it is to Fuel what ethers.js is to Ethereum, plus a build tool that bridges the Sway compiler to typed TypeScript bindings.

Audience inversion note. Although automated classification tags the repo as a web app, it is a library/framework/CLI. Throughout this guide the "operator" is a developer integrating or extending the SDK, and "deployment" means publishing packages and managing the toolchain — not running a server.


2. Architecture

2.1 High-level layers

            ┌─────────────────────────────────────────────────────────┐
            │                     fuels (umbrella)                     │
            │   re-exports every @fuel-ts/* package + the `fuels` CLI  │
            └───────────────┬─────────────────────────┬───────────────┘
                            │                         │
        ┌───────────────────▼──────────┐   ┌──────────▼───────────────┐
        │      High-level objects      │   │         CLI layer        │
        │  account · contract ·        │   │  init/build/deploy/dev/  │
        │  program · script · recipes  │   │  node/typegen/versions   │
        └───────────────┬──────────────┘   └──────────┬───────────────┘
                        │                              │
        ┌───────────────▼──────────────┐   ┌──────────▼───────────────┐
        │     Encoding & protocol      │   │     Codegen + binaries   │
        │  abi-coder · transactions ·  │   │  abi-typegen ·           │
        │  address · math · hasher     │   │  @internal/forc ·        │
        │  crypto · utils · errors     │   │  @internal/fuel-core     │
        └──────────────────────────────┘   └──────────────────────────┘

The dependency direction is strictly downward: high-level objects (Contract, Wallet) build on the encoding/protocol layer (abi-coder, transactions), which builds on primitives (math, crypto, errors). The CLI sits beside the runtime and pulls in abi-typegen plus the binary-management packages.

2.2 Package inventory

Published runtime packages (@fuel-ts/*)

Package Responsibility
account The largest package. Account, Wallet (locked/unlocked), HDWallet, Mnemonic, Signer, WalletManager (+ vaults/storages), Predicate, the Provider, transaction requests/responses/summaries, connectors (Fuel, FuelConnector), assets, and coin-consolidation utilities
contract ContractFactory (deploy), contract loader scripts, contract ID/root helpers
program The invocation-scope engine (FunctionInvocationScope, multicall, Script-request base) shared by contracts/scripts
script The Script high-level class
abi-coder Binary encode/decode of every Sway type — the Interface class and the Coder family (StructCoder, EnumCoder, VecCoder, OptionCoder, B256Coder, BigNumberCoder, …)
abi-typegen Code generator: ABI JSON → typed TS classes; ships the fuels-typegen CLI
transactions Transaction & receipt coders (the wire format)
address Address parsing/conversion (b256, bech32-style, EVM addresses)
crypto encrypt/decrypt, keccak256, scrypt, pbkdf2, randomBytes, with separate node and browser implementations behind one API
hasher Hashing helpers (sha256, address hashing)
math The BN big-number type and bn() factory
merkle Binary / sparse / sum Merkle tree implementations
utils Shared helpers, bytecode (de)compression, test-utils, default consensus key
errors FuelError + the ErrorCode enum (the single error taxonomy)
versions Version compatibility checking + the versions CLI
recipes Pre-built reusable contracts (e.g. the SRC-14 owned proxy)
logger A debug-based logger with Fuel-aware formatters

Aggregator & tooling packages

Package Role
fuels Umbrella: re-exports all of the above + FuelAsm (@fuels/vm-asm) + the CLI
create-fuels npm create fuels scaffolder
@internal/forc Downloads/installs the forc binary per platform
@internal/fuel-core Downloads/installs the fuel-core binary per platform
@internal/tsup Shared tsup bundler configurations
@internal/check-imports, check-tests CI integrity checks

The umbrella's public surface is defined entirely by packages/fuels/src/index.ts, which re-exports every sub-package. This barrel is the authoritative list of what import { … } from 'fuels' exposes.

2.3 Source tree

fuels-ts/
├── packages/          # ~20 published packages, each: src/ (barrel index.ts) + test/
│   ├── fuels/         #   umbrella + CLI (src/cli.ts, src/cli/commands/*)
│   ├── account/       #   Provider, Wallet, Predicate, tx requests (largest)
│   ├── abi-coder/     #   Interface + Coder family
│   ├── abi-typegen/   #   ABI → TS codegen + fuels-typegen CLI
│   ├── contract/ program/ script/ transactions/ address/ math/ …
│   └── create-fuels/  #   scaffolding CLI + templates
├── apps/
│   ├── docs/          # VitePress docs site; src/guide/**/snippets/*.ts are tested
│   ├── docs-api/      # generated API reference
│   └── demo-*/        # runnable example apps (nextjs, react-vite, bun, nodejs-esm)
├── templates/         # create-fuels templates (vite, nextjs)
├── internal/          # @internal/forc, @internal/fuel-core, tsup, check-*
└── scripts/           # release, changeset, forc-version, coverage tooling

Note

Most of the 2,000+ files are Sway test fixtures under packages/*/test/fixtures/forc-projects/** and docs snippets. The actual SDK surface is the packages/*/src/ trees, and the cleanest map to it is each package's src/index.ts barrel.


3. System Requirements

Concern Requirement
Node.js ^20, ^22, or ^24
Package manager (consumers) npm / pnpm / yarn / bun
Package manager (contributors) pnpm ^9.4.0 (declared packageManager)
Sway compiler forc — version pinned per SDK release
Node binary fuel-core — version pinned per SDK release
Browser Modern evergreen browsers (a dedicated browser build ships)

The forc/fuel-core versions are not free-floating: create-fuels writes a fuel-toolchain file pinning forc and fuel-core to the versions exported by @fuel-ts/versions, on the testnet channel. The fuels versions command exists precisely to catch drift between the installed binaries and the SDK's expected versions.


4. Configuration Mastery — fuels.config.ts

The fuels CLI is driven by a single config file resolved (via JoyCon) as fuels.config.{ts,js,cjs,mjs} walking up from the working directory. It is bundled and evaluated at runtime (bundle-require + esbuild), so it can be authored in TypeScript. Define it with createConfig for type-safety. Validation is enforced by a yup schema (output is the only strictly required field).

4.1 Full field reference

Field Type Default Notes
output string — Required. Directory for generated TypeScript. Resolved against the config's dir.
workspace string — Path to a Forc workspace. Mutually exclusive with contracts/scripts/predicates.
contracts string[] [] Individual contract program paths.
scripts string[] [] Individual script program paths.
predicates string[] [] Individual predicate program paths.
autoStartFuelCore boolean true Auto-start a local fuel-core during dev/node.
fuelCorePort number 4000 Port for the auto-started node.
providerUrl string process.env.FUEL_NETWORK_URL ?? http://127.0.0.1:4000/v1/graphql Network the CLI deploys to.
privateKey string defaultConsensusKey Deployer key. Override via the MY_PRIVATE_KEY env var in real deployments.
forcPath string resolved on PATH Path to the forc binary.
fuelCorePath string resolved on PATH Path to the fuel-core binary.
forcBuildFlags string[] [] Extra flags to forc build. Presence of --release selects buildMode: 'release', else 'debug'.
deployConfig object | fn {} Per-deploy options (storage slots, configurables).
snapshotDir string — Chain-config snapshot directory; watched by dev/node.
onBuild / onDeploy / onDev / onNode / onFailure callbacks — Lifecycle hooks invoked by the CLI.

Two derived fields are computed at load time and merged into the in-memory config: basePath (the config dir), configPath (the resolved file), and buildMode ('release' if --release is in forcBuildFlags, else 'debug'). The buildMode selects the artifact directory the CLI reads from: out/{buildMode}/{name}.bin, …-abi.json, and …-storage_slots.json.

Important

output must be a valid string or validateConfig rejects the file. workspace must point at a directory whose Forc.toml declares [workspace]; pointing it at a single program throws WORKSPACE_NOT_DETECTED and suggests using contracts/scripts/predicates instead.

4.2 Environment variables

The CLI and examples read a handful of env vars:

Variable Used for
FUEL_NETWORK_URL Default providerUrl when not set in config
MY_PRIVATE_KEY Deployer key in fuels.config.ts
FUEL_CORE_PATH Locating the fuel-core binary in test setup

Caution

The default privateKey is the well-known local consensus key — convenient for fuels dev against a local node, never for testnet/mainnet. Always inject a real key via MY_PRIVATE_KEY (or another secret source) for non-local deployments.


5. The Sway → TypeScript Codegen Pipeline

This is the SDK's signature subsystem: turning compiled Sway programs into typed TypeScript.

5.1 The build/deploy flow (fuels build, fuels deploy)

forc build (Sway compiler)
   └─ out/{debug|release}/{name}.bin
      out/{debug|release}/{name}-abi.json
      out/{debug|release}/{name}-storage_slots.json
        │
        ▼
abi-typegen  →  typed TS classes  (Contract/Factory, Script[+Loader], Predicate[+Loader])
        │
        ▼
fuels deploy → deploys, writes contract-ids.json, regenerates factory classes with loader code

forcUtils.ts is the glue: it reads each program's Forc.toml to discover the project name, the Sway program type (contract/script/predicate/library), and computes the .bin/-abi.json/-storage_slots.json paths from buildMode. findPrograms() globs for *.toml, filters out the workspace root and libraries, and classifies the rest by reading the ;-terminated program-type line in each src/main.sw.

deploy() (in cli/commands/deploy) runs in order: deploy contracts → save contract-ids.json → deploy scripts → save script files → deploy predicates → save predicate files → fire the onDeploy callback → regenerate factory classes so they embed loader bytecode.

5.2 abi-typegen internals

The generator (AbiTypeGen) consumes the new ABI JSON shape (JsonAbiNew; an older shape is transpiled forward via transpileAbi). For each program it builds an Abi model exposing types, functions, configurables, commonTypesInUse, and bytecode, then renders Handlebars (.hbs) templates:

  • Contract → renderMainTemplate emits the typed contract class with per-function encoders/decoders, struct/enum typedefs, the embedded ABI JSON, and storage slots. Base members imported: FunctionFragment, InvokeFunction.
  • Predicate → requires a main() function (else ABI_MAIN_METHOD_MISSING); imports Predicate, Provider, InputValue, PredicateParams, decompressBytecode; embeds compressed bytecode.
  • Script → also requires main(); imports Script, Account, decompressBytecode.
  • index → renderIndexTemplate re-exports the generated members.

Struct/enum/import formatting is handled by formatStructs/formatEnums/formatImports. The CLI surface (fuels-typegen) is a commander program with -i/--inputs, -o/--output, mutually-exclusive -c/-s/-p, and -S/--silent; resolveProgramType defaults to CONTRACT when none is specified.

Note

Predicates and scripts can be deployed as reusable loader bytecode. After fuels deploy, the generator re-emits *Loader classes that reference the on-chain blob, keeping per-transaction payloads small. This is why deploy regenerates types as its final step.


6. The Transaction-Assembly Engine (UTXO)

Fuel is UTXO-based, so the hardest problems in the SDK are coin selection and fee estimation. This logic lives in @fuel-ts/account under providers/.

6.1 Transaction request types

providers/transaction-request/ defines a request hierarchy, each a coder over the wire format:

Request Used for
ScriptTransactionRequest Script execution and transfers (the workhorse)
CreateTransactionRequest Contract creation/deployment
BlobTransactionRequest Uploading bytecode blobs (loader pattern)
UpgradeTransactionRequest / UploadTransactionRequest Chain/state upgrades

Requests expose addCoinOutput, addContractInputAndOutput, addResources, addWitness/updateWitness, setData, and getTransactionId(chainId).

6.2 assembleTx — the modern funding API

provider.assembleTx({ request, feePayerAccount, accountCoinQuantities }) is the recommended way to fund and estimate any hand-built request. The caller declares which account supplies which { amount, assetId } and where change goes (changeOutputAccount); the engine selects coins, estimates gas/fee, and returns a ready-to-send assembledRequest. Because assembly can mutate the request (adding inputs/outputs and changing the tx ID), signatures must be (re)applied after assembly — see the signing flow in the User Guide.

6.3 Coin management utilities

@fuel-ts/account exports UTXO-shaping helpers:

Export Purpose
consolidateCoins / consolidateCoinsIfRequired Merge many small coins into few (avoids the input-count limit)
getAllCoins Fetch every coin for an asset across pages
assembleTransferToContractScript Build the script data for contract transfers
Account.batchTransfer Many transfers in one transaction
Account.generateFakeResources Synthesize resources for dry-runs

The Provider carries an optional resource cache (resourceCacheTTL) to prevent the same coin from being selected by two in-flight transactions (double-spend protection at the client level). Provider.ENABLE_RPC_CONSISTENCY toggles a cross-node consistency check.

6.4 Transaction lifecycle

build request → assembleTx (select coins, estimate fee)
   → sign (if required) → sendTransaction / .call()
   → TransactionResponse → waitForResult()
   → TransactionSummary (status, receipts, fee, decoded logs)

transaction-summary/ assembles human-readable summaries from raw receipts, including operation classification and fee calculation. transaction-response/getDecodedLogs and getAllDecodedLogs turn receipts into typed log values (and the grouped-by-contract logs the User Guide demonstrates).


7. The ABI Coder

@fuel-ts/abi-coder is the binary serialization layer. The Interface class wraps an ABI and exposes functions.<name>.encodeArguments(...) / decodeOutput(...). Encoding is delegated to a family of Coder subclasses, one per Sway type:

ArrayCoder, B256Coder, B512Coder, BigNumberCoder, BooleanCoder, ByteCoder, EnumCoder, NumberCoder, OptionCoder, RawSliceCoder, StdStringCoder, StrSliceCoder, StringCoder, StructCoder, TupleCoder, VecCoder.

It also exports the protocol size constants (WORD_SIZE, BYTES_32, ASSET_ID_LEN, CONTRACT_ID_LEN, INPUT_COIN_FIXED_SIZE, SCRIPT_FIXED_SIZE, calculateVmTxMemory) and the encoding version flag ENCODING_V1. The new ABI type (JsonAbi, from types/JsonAbiNew) is the canonical shape; legacy ABIs are transpiled.

Note

The coder family is the lowest-level public contract in the SDK. If you ever need to encode/decode against a raw ABI without a generated class, construct an Interface directly — this is what the generated classes do under the hood.


8. Binary Management — forc & fuel-core

The SDK does not bundle the Rust binaries; the @internal/forc and @internal/fuel-core packages download the correct binary per platform/architecture at install time (lib/install.js, lib/shared.js). They detect the architecture and throw Unsupported arch ${process.arch} for unsupported platforms, and validate the version string.

At runtime the CLI's tryFindBinaries resolves forcPath/fuelCorePath either from config or the system PATH; if a binary is missing it throws with a message listing each missing binary and a link to the installation guide. autoStartFuelCore (in the dev/node commands) spawns a fuel-core child process on fuelCorePort and tears it down on config change or shutdown.

Tip

For consumers, the recommended install path is fuelup, which manages matched forc/fuel-core toolchains by channel. The @internal/* download packages exist mainly so the monorepo's own tests and the scaffolded templates get a known-good binary without a manual fuelup step.


9. Security

Surface Handling
Private keys Never logged. WalletUnlocked holds the key in memory; WalletLocked holds only an address. lock() drops the key.
Keystores Wallet.encrypt/fromEncryptedJson use scrypt-derived AES (the crypto package), with separate hardened node/browser implementations.
WalletManager Vaults stay encrypted until unlock(password); lock() clears secrets. updatePassphrase rotates without re-importing keys.
Default consensus key Used only as the local-dev deployer default; documented as unsafe for real networks (override via MY_PRIVATE_KEY).
Double-spend protection Provider resourceCacheTTL prevents reusing a coin across concurrent in-flight transactions.
Predicates Spend authorization is enforced on-chain by the predicate program, not by client trust.
Network transport requestMiddleware allows injecting auth/credentials; timeout and retryOptions bound exposure to a hung or flaky node.
Configurable validation Configurable constants are type-checked against the ABI before deploy, rejecting malformed structs.

Caution

Treat fuels.config.ts as code: it is bundled and executed by the CLI. Do not commit real privateKey values into it — read them from the environment.


10. Operations — the CLI dev loop

The fuels CLI (packages/fuels/src/cli.ts) is a commander program named fuels with global -D/--debug and -S/--silent flags (wired through a preAction hook into configureLogging). Commands:

Command Action module Behavior
init commands/init Discovers programs, writes fuels.config.ts (errors if it exists)
build commands/build forc build + typegen; --deploy also deploys
deploy commands/deploy Deploys contracts→scripts→predicates, saves IDs, regenerates types
dev commands/dev autoStartFuelCore → build+deploy → watch config/Sway/snapshot with chokidar, rebuild on change
node commands/node Start fuel-core from config and watch for config changes
typegen delegates to @fuel-ts/abi-typegen/cli ABI → TS
versions delegates to @fuel-ts/versions/cli Compatibility check

The dev/node commands wrap their actions in withConfig/withProgram/withBinaryPaths higher-order handlers that load + validate config and resolve binaries before running, and route failures through withConfigErrorHandler (which can invoke the onFailure hook).

10.1 Local development workflow

pnpm install          # install workspace
pnpm build:packages   # turbo build all publishable packages (excludes docs/templates)
pnpm test:node        # vitest node project
pnpm test:browser     # vitest browser project (Playwright-backed)
pnpm lint             # type-check + eslint + prettier

The root package.json exposes the full operational surface: turbo run build for the dependency-aware build graph; vitest split into node and browser projects with separate configs; coverage merge/diff scripts; forc:check/forc:verify/forc:update to keep the Sway toolchain pinned; and changeset:* scripts for release.


11. Testing Strategy

Layer Tooling
Unit & integration Vitest, split into node and browser projects (vitest.node.config.mts, vitest.browser.config.mts)
Browser execution @vitest/browser over Playwright
Coverage Istanbul, with test:coverage-merge / test:coverage-diff to combine node+browser and gate PRs
Test selection scripts/tests-find.sh filters by --node/--browser/--e2e/--integration/--network
End-to-end Real network tests gated on NETWORK_TEST_URL + NETWORK_TEST_PVT_KEY env vars
Docs snippets Every apps/docs/src/guide/**/snippets/*.ts is a compiled, executed test (tagged @group node/@group browser)
Ephemeral node launchTestNode() (in @fuel-ts/account/utils test-utils) spins up fuel-core with funded wallets, auto-torn-down via using
Forc fixtures turbo run test:forc compiles the Sway fixture projects under each package's test/fixtures/forc-projects/**

The docs-as-tests approach is notable: the user-facing examples cannot drift from the API, because they are typechecked and run in CI. expectToThrowFuelError (from @fuel-ts/errors/test-utils) asserts a specific FuelError code is thrown.


12. Error Code Reference

All SDK errors are FuelError instances with a stable string code from the ErrorCode enum (packages/errors/src/error-codes.ts). FuelError also carries metadata, rawError, and VERSIONS (the SDK/binary versions at throw time), and FuelError.parse() rehydrates a serialized error (rejecting unknown codes). Selected codes by domain:

Domain Representative codes
ABI / codegen no-abis-found, abi-main-method-missing, configurable-not-found, type-not-supported, invalid-decode-value, unsupported-encoding-version, bin-file-not-found
Config / CLI config-file-not-found, config-file-already-exists, workspace-not-detected
Address invalid-address, invalid-evm-address, invalid-b256-address
Provider chain-info-cache-empty, missing-provider, connection-refused, invalid-url, response-body-empty
Wallet / account invalid-public-key, wallet-manager-error, hd-wallet-error, account-required, unlocked-wallet-required, invalid-password
Funds / coins not-enough-funds-or-max-coins-reached, not-enough-funds, max-coins-reached, unable-to-consolidate-coins, no-coins-to-consolidate, coins-asset-id-mismatch
Transaction gas-limit-too-low, max-fee-too-low, gas-price-too-low, transaction-failed, transaction-squeezed-out, invalid-configurable-constants, max-inputs-exceeded, max-outputs-exceeded, asset-burn-detected, change-output-collision, contract-size-exceeds-limit
Mnemonic invalid-mnemonic, invalid-entropy, invalid-seed, invalid-checksum, invalid-word-list
Script script-reverted, script-return-invalid-type
Node / misc node-launch-failed, rpc-consistency, not-implemented, unknown

Tip

Branch on error.code, never the message — messages are human-facing and may change; codes are part of the contract. The full enum is the canonical, exhaustive list.


13. Known Issues, Tech Debt & Roadmap

Drawn from the project's own issue tracker at analysis time:

Issue Area Notes
#3803 (open) UTXO "No Coins Available or exceeding 255 Coin Limit" — the coin-input ceiling; mitigated by consolidateCoins, tracked for a smoother flow (#3808 auto-consolidation).
#3935 (open) Logs Allow filtering logs by type.
#3593 (open) Configurables Support dynamic configurables.
#3941 (open) Typegen Generated relative imports omit the .js extension (ESM resolution).
#3930 (open) Assets Deprecate assets.
#3724 (open) Tooling Migrate eslint + prettier to biome.
#2477 (open) Architecture Consider merging hasher into crypto.
#2478 (open) Architecture Consider merging script into program.

These reflect the SDK's direction: smoother UTXO management (auto-consolidation), richer log handling, ESM-correct codegen, and package consolidation (hasher→crypto, script→program) to shrink the dependency graph.


14. Release & Distribution

Step Mechanism
Versioning Changesets (@changesets/cli); changeset:next, changeset:version-with-docs
Build turbo run build (dependency-aware) → each package bundled by tsup to CJS/ESM/IIFE with sourcemaps and keepNames
Publish changeset:publish over the workspace; packages are versioned in lock-step
Deprecation release-deprecate.ts
Toolchain sync forc:update/forc:verify/verify-forc-version keep the pinned Sway compiler current
Dependency hygiene knip (unused deps), syncpack (version alignment across the workspace)

Because every @fuel-ts/* package is published in lock-step and the umbrella fuels re-exports them, a consumer almost always depends on a single fuels version and gets a consistent set of sub-packages.


15. Quick Reference

Package dependency direction

fuels  →  account · contract · program · script · recipes   (high-level)
           │
           ▼
        abi-coder · transactions · address                   (encoding/protocol)
           │
           ▼
        math · crypto · hasher · merkle · utils · errors      (primitives)

CLI(fuels)  →  abi-typegen · @internal/forc · @internal/fuel-core

Key files for contributors

Want to change… Read
Public SDK surface packages/fuels/src/index.ts (barrel)
CLI commands packages/fuels/src/cli.ts + cli/commands/*
Config loading/validation packages/fuels/src/cli/config/{loadConfig,validateConfig,forcUtils}.ts
Codegen packages/abi-typegen/src/** (templates in templates/*/main.ts + .hbs)
Coin selection / funding packages/account/src/providers/** (assembleTx, transaction-request)
Binary encode/decode packages/abi-coder/src/**
Error taxonomy packages/errors/src/error-codes.ts

Operational commands

pnpm install && pnpm build:packages   # bootstrap + build
pnpm test:node                         # run node tests
pnpm lint                              # type + eslint + prettier
pnpm changeset                         # record a release note
npx fuels versions                     # check forc/fuel-core compatibility