Skip to main content
A Hedera account is required to interact with any network service, since every transaction and query fee is paid from an account. You can create a previewnet or testnet account on the Hedera Developer Portal, or use a third-party wallet to generate a free mainnet account. This page covers programmatic account creation with AccountCreateTransaction(). The transaction must be signed and paid for by an existing account. To obtain the new account ID, request the receipt of the transaction. For a complete list of account properties, see the accounts overview.
Recommended default for EVM compatibility: Create accounts with an ECDSA key and set the EVM Address from Public Key at creation. This enables native compatibility with EVM wallets, JSON-RPC tooling, and smart-contract interactions. Use setECDSAKeyWithAlias() (or setKeyWithAlias() with an ECDSA key) to do this in a single call.

Transaction fees and signing

  • The account paying for the transaction fee is required to sign the transaction.
  • The sender also pays the maxAutoAssociations fee and the rent for the first auto-renewal period.
  • See the transaction and query fees table for the base transaction fee.
  • Use the Hedera fee estimator to estimate cost.

Constructor

Methods

Exactly one of setKey, setKeyWithAlias, setECDSAKeyWithAlias, or setKeyWithoutAlias is required. See Setting the key and alias for which to use.

EVM address from public key

Setting an ECDSA-derived EVM address at creation makes the account natively addressable from EVM wallets, JSON-RPC, and Solidity (msg.sender). The address is the rightmost 20 bytes of the Keccak-256 hash of the ECDSA public key. To enable this behavior, use the one-argument key-with-alias method for your SDK (setECDSAKeyWithAlias() in most SDKs, setKeyWithAlias() in Java). See Setting the key and alias for the full breakdown.Immutability: The EVM address is bound to the original ECDSA public key and does not change if you later rotate keys via CryptoUpdateTransaction. Integrations keyed to that EVM address (smart-contract permissions, address-based access lists) will continue to reference the original address.If key rotation is required: Use setKeyWithoutAlias() instead. The account will fall back to its EVM Address from Account ID (the long-zero form).Recovery model: If keys are compromised or must be replaced, create a new account with a new ECDSA key, then migrate assets and state. Do not rely on key rotation to preserve the same EVM identity.

High-volume entity creation

This transaction supports high-volume entity creation (HIP-1313). Setting setHighVolume(true) routes the transaction through dedicated high-volume throttle capacity with variable-rate pricing. Always pair this with setMaxTransactionFee() to cap your costs.

Maximum auto-associations

The maxAutoAssociations property determines how many automatic token associations an account allows. Reference: HIP-904.

Setting the key and alias

AccountCreateTransaction provides three ways to set the account key and the EVM address. Which one you choose depends on whether you want EVM compatibility and whether you plan to rotate the account key later. The method names below use the JavaScript SDK; see the per-SDK quick reference for the equivalent in each language.
To assign a specific, pre-computed EVM address instead of deriving one from the key, combine setKeyWithoutAlias(key) with setAlias(evmAddress). This is the HIP-583 pattern, useful when you already hold the target EVM address (for example, when migrating an existing EVM address).

Private or public key input

Whether the one-shot method accepts a public key or requires a private key depends on the SDK (see the per-SDK quick reference):
  • JavaScript, Java, Python, and Go accept either a public or a private ECDSA key. The EVM address is derived from the public component, so the choice is only about what key material you hand the builder. Pass a public key when the private key is held externally (a hardware wallet, HSM, or another party); the create transaction must still be signed by the corresponding private key.
  • Rust, C++, and Swift accept a private key only. If you hold just a public key (HSM or external-signer flows), use the manual path instead: set the key without an alias and set the alias explicitly from the derived address, for example setKeyWithoutAlias(publicKey) with setAlias(publicKey.toEvmAddress()). See the HSM-signing tutorials.
In the JavaScript SDK, the four derive variants are: (In Java, the one-argument forms use setKeyWithAlias(key) rather than setECDSAKeyWithAlias.) When you use a separate alias key, both the account key and the alias key must sign the transaction.

Per-SDK quick reference

Java naming: setKeyWithAlias(key) with one argument is Java’s equivalent of setECDSAKeyWithAlias(key) in other SDKs. The two-argument overload setKeyWithAlias(key, ecdsaKey) is used when the account key and the alias-derivation key differ.Long-zero address parallel: Rust and C++ do not expose toEvmAddress() on AccountId. They expose to_solidity_address() / toSolidityAddress() instead, which returns the same long-zero form (the EVM Address from Account ID). Functionally equivalent, just a naming difference.Swift throws: Swift’s AccountId.toEvmAddress() is declared throws, so call sites need try (e.g., try accountId.toEvmAddress()).

Example


Deriving the EVM address (toEvmAddress helper)

If you call setAlias(...) directly instead of a one-shot key-with-alias method, derive the EVM address from the ECDSA public key with the SDK helper:
In most cases, prefer setECDSAKeyWithAlias(publicKey), which sets the key and derives the alias in one call. Use the toEvmAddress helper when you need the value separately (for logging, validation, or pairing with setAlias).
Note on overloading: toEvmAddress is also exposed on AccountId in some SDKs. AccountId.toEvmAddress() returns the EVM Address from Account ID (the long-zero form), not the EVM Address from Public Key. For EVM compatibility, you want the PublicKey variant. AccountId.toEvmAddress() is not implemented in Rust and is named toSolidityAddress() in C++.

Verifying the EVM address

After creating an account, confirm the EVM Address from Public Key was set correctly using either the SDK or the mirror node.

Using the SDK

If the account was created with setKeyWithoutAlias(...), contractAccountId returns the EVM Address from Account ID (long-zero form, starting with 24 zero hex characters). If it was created with setECDSAKeyWithAlias(...) or equivalent, it returns the EVM Address from Public Key.

Using the mirror node REST API

The evm_address field in the response is the canonical EVM address for the account.

Common pitfalls

Creating an ECDSA account with setKey() only. The account is valid and can hold HBAR, but it has no EVM Address from Public Key. It falls back to its EVM Address from Account ID (long-zero form), which means:
  • It is not natively addressable from MetaMask or other EVM wallets keyed to the public-key EVM address.
  • Solidity contracts that compare msg.sender against the expected EVM address will not match.
  • JSON-RPC tooling expecting an ECDSA-derived address sees an unexpected long-zero address.
Use setECDSAKeyWithAlias(publicKey) (or setKeyWithAlias(publicKey) with an ECDSA key) instead.
Using deprecated PrivateKey.generate(). This helper silently returns an ED25519 key, which cannot be used to derive an EVM address. Use PrivateKey.generateECDSA() for new accounts.

Common consensus errors


Get transaction values