Overview
The createAccount action creates a new NEAR account. This action must be combined with other actions to be useful, as a new account needs tokens and an access key to be functional.
Signature
createAccount(): CreateAccountAction
Parameters
No parameters required.
Returns
A CreateAccountAction object:
{
actionType: 'CreateAccount'
}
Basic Example
import {
createAccount,
transfer,
addFullAccessKey,
near,
randomEd25519KeyPair
} from '@near-api-ts/universal';
const newKeyPair = randomEd25519KeyPair();
await signer.executeTransaction({
intent: {
receiverAccountId: 'sub.alice.near',
actions: [
createAccount(),
transfer({ amount: near('10') }),
addFullAccessKey({ publicKey: newKeyPair.publicKey })
]
}
});
console.log('Account created successfully');
console.log('New account private key:', newKeyPair.secretKey);
createAccount() must always be used with:
- A
transfer() action to fund the account
- An
addFullAccessKey() or addFunctionCallKey() action to give the account access keys
Subaccount Creation
Create a subaccount of the signer’s account:
import {
createAccount,
transfer,
addFullAccessKey,
near,
randomEd25519KeyPair
} from '@near-api-ts/universal';
const newKeyPair = randomEd25519KeyPair();
await signer.executeTransaction({
intent: {
receiverAccountId: 'app.alice.near', // subaccount of alice.near
actions: [
createAccount(),
transfer({ amount: near('5') }),
addFullAccessKey({ publicKey: newKeyPair.publicKey })
]
}
});
Only the parent account can create subaccounts. For example, only alice.near can create *.alice.near accounts.
Create and Deploy Contract
import {
createAccount,
transfer,
deployContract,
addFullAccessKey,
near,
randomEd25519KeyPair
} from '@near-api-ts/universal';
import { readFile } from 'fs/promises';
const wasmBytes = await readFile('./contract.wasm');
const newKeyPair = randomEd25519KeyPair();
await signer.executeTransaction({
intent: {
receiverAccountId: 'contract.alice.near',
actions: [
createAccount(),
transfer({ amount: near('10') }),
addFullAccessKey({ publicKey: newKeyPair.publicKey }),
deployContract({ wasmBytes })
]
}
});
Create with Function Call Key
Create an account with limited permissions:
import {
createAccount,
transfer,
addFunctionCallKey,
near,
randomEd25519KeyPair
} from '@near-api-ts/universal';
const newKeyPair = randomEd25519KeyPair();
await signer.executeTransaction({
intent: {
receiverAccountId: 'limited.alice.near',
actions: [
createAccount(),
transfer({ amount: near('5') }),
addFunctionCallKey({
publicKey: newKeyPair.publicKey,
contractAccountId: 'app.near',
allowedFunctions: ['claim_reward', 'vote'],
gasBudget: near('0.25')
})
]
}
});
Create Multiple Accounts
Create several accounts in sequence:
import {
createAccount,
transfer,
addFullAccessKey,
near,
randomEd25519KeyPair
} from '@near-api-ts/universal';
const accounts = ['app', 'api', 'storage'];
for (const name of accounts) {
const keyPair = randomEd25519KeyPair();
await signer.executeTransaction({
intent: {
receiverAccountId: `${name}.alice.near`,
actions: [
createAccount(),
transfer({ amount: near('5') }),
addFullAccessKey({ publicKey: keyPair.publicKey })
]
}
});
console.log(`Created ${name}.alice.near`);
console.log(`Private key: ${keyPair.secretKey}`);
}
Minimum Balance Requirements
import { near } from '@near-api-ts/universal';
// Minimum for account creation (varies by network)
const MAINNET_MIN = near('0.001');
const TESTNET_MIN = near('0.001');
// Recommended initial balance
const RECOMMENDED = near('1');
// For contract accounts (need more for storage)
const CONTRACT_MIN = near('5');
If you don’t transfer enough NEAR during account creation, the transaction will fail. The minimum is typically around 0.001 NEAR, but more is recommended.
Named Account Creation
Create top-level named accounts (requires special permissions):
// This only works if you have permission to create top-level accounts
// (e.g., via registrar contract)
await signer.executeTransaction({
intent: {
receiverAccountId: 'newuser.near',
actions: [
createAccount(),
transfer({ amount: near('10') }),
addFullAccessKey({ publicKey: newKeyPair.publicKey })
]
}
});
Creating top-level .near accounts requires going through a registrar contract. Most applications create subaccounts instead.
Implicit Account Creation
Create an implicit account (based on public key):
import {
transfer,
near,
randomEd25519KeyPair
} from '@near-api-ts/universal';
const newKeyPair = randomEd25519KeyPair();
const implicitAccountId = newKeyPair.publicKey.replace('ed25519:', '');
// Implicit accounts are created automatically by sending tokens
await signer.executeTransaction({
intent: {
receiverAccountId: implicitAccountId,
action: transfer({ amount: near('1') })
}
});
console.log('Implicit account created:', implicitAccountId);
console.log('Private key:', newKeyPair.secretKey);
Implicit accounts (64 hex characters) are created automatically when you send them tokens. No createAccount() action is needed.
Error Handling
import {
createAccount,
transfer,
addFullAccessKey,
near,
randomEd25519KeyPair,
isNatError
} from '@near-api-ts/universal';
try {
const newKeyPair = randomEd25519KeyPair();
await signer.executeTransaction({
intent: {
receiverAccountId: 'sub.alice.near',
actions: [
createAccount(),
transfer({ amount: near('10') }),
addFullAccessKey({ publicKey: newKeyPair.publicKey })
]
}
});
} catch (error) {
if (isNatError(error)) {
if (error.kind === 'MemorySigner.ExecuteTransaction.Rpc.Transaction.Action.CreateAccount.AlreadyExist') {
console.error('Account already exists');
} else if (error.kind === 'MemorySigner.ExecuteTransaction.Rpc.Transaction.Signer.Balance.TooLow') {
console.error('Insufficient balance to create account');
}
}
}
Safe Variant
const action = createAccount();
const result = await signer.safeExecuteTransaction({
intent: {
receiverAccountId: 'sub.alice.near',
actions: [
action,
transfer({ amount: near('10') }),
addFullAccessKey({ publicKey: newKeyPair.publicKey })
]
}
});
if (result.ok) {
console.log('Account created:', result.value.transactionHash);
} else {
console.error('Creation failed:', result.error.kind);
}
Common Errors
MemorySigner.ExecuteTransaction.Rpc.Transaction.Action.CreateAccount.AlreadyExist - Account already exists
MemorySigner.ExecuteTransaction.Rpc.Transaction.Signer.Balance.TooLow - Insufficient balance
- Transaction must include transfer - Account creation requires funding
- Transaction must include access key - Account needs at least one key
Best Practices
DO:
- Always include a transfer action with sufficient balance
- Always add at least one access key
- Store the new account’s private key securely
- Test account creation on testnet first
- Use descriptive subaccount names
- Validate account names before creation
DON’T:
- Don’t create accounts without sufficient funding
- Don’t lose the private key - it can’t be recovered
- Don’t create accounts without access keys
- Don’t assume account names are available
- Don’t forget that only parent accounts can create subaccounts
Account Name Rules
- Minimum length: 2 characters
- Maximum length: 64 characters
- Allowed characters:
a-z, 0-9, -, _, .
- Must not start or end with
.
- Must not have consecutive
. characters
- Subaccounts use format:
sub.parent.near
See Also