---
title: Writing to the Network
description:
  Learn how to write data to the Solana network by sending transactions and
  instructions. Follow step-by-step examples to transfer SOL and create a token
  mint using Solana Kit.
---

In the previous section, you learned how to
[read data from the Solana network](/docs/intro/quick-start/reading-from-network)
by fetching accounts. Writing data to the Solana network requires a
[transaction](/docs/core/transactions). A transaction contains one or more
[instructions](/docs/core/instructions), and each instruction invokes a program.

Programs define the business logic for each instruction. When you send a
transaction, the Solana runtime executes the transaction's instructions in
order. Transactions are atomic. Either every instruction in the transaction
succeeds, or the entire transaction fails.

The examples in this section show how to:

1. Transfer SOL between accounts
2. Create a new token mint

## Transfer SOL

The example below transfers SOL from one account to another. Only the program
designated as an account's owner can modify the account's data or deduct
lamports from its balance. Wallet accounts are owned by the
[System Program](/docs/core/programs/builtin-programs#the-system-program), so
transferring SOL between wallet accounts requires an instruction that invokes
the System Program's
[transfer](https://github.com/anza-xyz/agave/blob/v2.1.11/programs/system/src/system_processor.rs#L183-L213)
instruction. The source account must also sign the transaction.

<WithNotes>

<CodeTabs flags="r">

```ts !! title="Transfer SOL"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getTransferSolInstruction } from "@solana-program/system";

// !tooltip[/createClient/] client
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

// !tooltip[/receiver/] receiver
const receiver = await generateKeyPairSigner();

// !tooltip[/transferInstruction/] transferInstruction
const transferInstruction = getTransferSolInstruction({
  source: client.payer,
  destination: receiver.address,
  amount: lamports(10_000_000n)
});

// !tooltip[/sendTransaction/] sendTransaction
const result = await client.sendTransaction([transferInstruction]);

console.log("Transaction Signature:", result.context.signature);

// !tooltip[/balances/] balances
const { value: senderBalance } = await client.rpc
  .getBalance(client.payer.address)
  .send();
const { value: receiverBalance } = await client.rpc
  .getBalance(receiver.address)
  .send();

console.log("Sender Balance:", senderBalance);
console.log("Receiver Balance:", receiverBalance);
```

</CodeTabs>

### !client

Create a Kit client for the local validator. `generatedPayer()` adds a payer
signer, `solanaRpc()` adds RPC and transaction-sending capabilities,
`rpcAirdrop()` adds `client.airdrop`, and `airdropPayer()` funds the payer with
test SOL.

### !receiver

Generate a signer for the account receiving SOL. The receiver does not need to
sign this transfer. If the receiver address does not already have an account,
receiving SOL creates a system account at that address.

### !transferInstruction

Build the System Program instruction that transfers lamports from the client
payer to the receiver.

### !sendTransaction

Send the instruction as a transaction. The Kit client fetches a recent
blockhash, sets the fee payer, signs with the required signers, sends the
transaction, and waits for confirmation.

### !balances

Fetch the sender and receiver balances after the transaction is confirmed.

</WithNotes>

<ScrollyCoding>

## !!steps

Create a Kit client for the local test validator. This snippet adds a payer
signer, connects to the local RPC endpoint, enables airdrops, and funds the
payer with test SOL for the transfer.

```ts title="Client setup"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));
```

```ts !! title="Transfer SOL"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getTransferSolInstruction } from "@solana-program/system";

// !focus(1:10)
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));
```

## !!steps

Generate a signer for the receiver. The sender is `client.payer`, which was
created by `generatedPayer()` and funded by `airdropPayer()`.

```ts title="Receiver signer"
const receiver = await generateKeyPairSigner();
```

```ts !! title="Transfer SOL"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getTransferSolInstruction } from "@solana-program/system";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

// !focus
const receiver = await generateKeyPairSigner();
```

## !!steps

<WithMentions>

The `getTransferSolInstruction()` helper creates a System Program instruction.
The instruction transfers SOL from the [`source`](mention:source) signer to the
[`destination`](mention:destination) address for the specified
[`amount`](mention:amount) of lamports.

```ts title="Transfer instruction"
const transferInstruction = getTransferSolInstruction({
  // !mention source
  source: client.payer,
  // !mention destination
  destination: receiver.address,
  // !mention amount
  amount: lamports(10_000_000n)
});
```

</WithMentions>

```ts !! title="Transfer SOL"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getTransferSolInstruction } from "@solana-program/system";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const receiver = await generateKeyPairSigner();

// !focus(1:5)
const transferInstruction = getTransferSolInstruction({
  source: client.payer,
  destination: receiver.address,
  amount: lamports(10_000_000n)
});
```

## !!steps

Call `client.sendTransaction()` with an array of instructions. The Kit client
turns the instructions into one transaction, signs with the signers attached to
the instructions, sends the transaction, and waits for confirmation.

```ts title="Send transaction"
const result = await client.sendTransaction([transferInstruction]);

console.log("Transaction Signature:", result.context.signature);
```

```ts !! title="Transfer SOL"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getTransferSolInstruction } from "@solana-program/system";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const receiver = await generateKeyPairSigner();

const transferInstruction = getTransferSolInstruction({
  source: client.payer,
  destination: receiver.address,
  amount: lamports(10_000_000n)
});

// !focus(1:3)
const result = await client.sendTransaction([transferInstruction]);

console.log("Transaction Signature:", result.context.signature);
```

## !!steps

After the transaction is confirmed, fetch both balances using `client.rpc`.

```ts title="Fetch balances"
const { value: senderBalance } = await client.rpc
  .getBalance(client.payer.address)
  .send();
const { value: receiverBalance } = await client.rpc
  .getBalance(receiver.address)
  .send();
```

```ts !! title="Transfer SOL"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getTransferSolInstruction } from "@solana-program/system";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const receiver = await generateKeyPairSigner();

const transferInstruction = getTransferSolInstruction({
  source: client.payer,
  destination: receiver.address,
  amount: lamports(10_000_000n)
});

const result = await client.sendTransaction([transferInstruction]);

console.log("Transaction Signature:", result.context.signature);

// !focus(1:6)
const { value: senderBalance } = await client.rpc
  .getBalance(client.payer.address)
  .send();
const { value: receiverBalance } = await client.rpc
  .getBalance(receiver.address)
  .send();

console.log("Sender Balance:", senderBalance);
console.log("Receiver Balance:", receiverBalance);
```

</ScrollyCoding>

## Create a token

The example below creates a new token mint using the
[Token Extensions Program](/docs/tokens/extensions). A mint account is the
account that defines a token's global settings, such as decimals, supply, mint
authority, and freeze authority.

Creating a mint account requires two instructions:

1. Invoke the System Program to create a new account owned by the Token
   Extensions Program.
2. Invoke the Token Extensions Program to initialize that account as a mint.

<WithNotes>

<CodeTabs flags="r">

```ts !! title="Create mint account"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
  fetchMint,
  getInitializeMintInstruction,
  getMintSize,
  TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";

// !tooltip[/createClient/] client
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

// !tooltip[/mint/] mint
const mint = await generateKeyPairSigner();

// !tooltip[/space/] space
const space = BigInt(getMintSize());

// !tooltip[/rent/] rent
const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();

// !tooltip[/createAccountInstruction/] createAccountInstruction
const createAccountInstruction = getCreateAccountInstruction({
  payer: client.payer,
  newAccount: mint,
  space,
  lamports: rent,
  programAddress: TOKEN_2022_PROGRAM_ADDRESS
});

// !tooltip[/initializeMintInstruction/] initializeMintInstruction
const initializeMintInstruction = getInitializeMintInstruction({
  mint: mint.address,
  decimals: 2,
  mintAuthority: client.payer.address,
  freezeAuthority: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

// !tooltip[/sendTransaction/] sendTransaction
const result = await client.sendTransaction([
  createAccountInstruction,
  initializeMintInstruction
]);

console.log("Mint Address:", mint.address);
console.log("Transaction Signature:", result.context.signature);

// !tooltip[/mintAccount/] mintAccount
const mintAccount = await fetchMint(client.rpc, mint.address);
console.log("Mint Account:", mintAccount);
```

</CodeTabs>

### !client

Create and fund a Kit client for the local validator. The funded payer pays
account rent and transaction fees.

### !mint

Generate a signer to use as the address of the new mint account. The signer
authorizes creation of that account.

### !space

Calculate the number of bytes required for a mint account with no extensions.

### !rent

Calculate the lamports required to make the mint account rent-exempt.

### !createAccountInstruction

Build the System Program instruction that creates the mint account and assigns
the account to the Token Extensions Program.

### !initializeMintInstruction

Build the Token Extensions Program instruction that writes the initial mint data
into the new account.

### !sendTransaction

Send both instructions as one transaction. Instruction order matters: the
account must be created before the account can be initialized.

### !mintAccount

Fetch the mint account after confirmation. The helper reads the account and
deserializes the mint account's data field into the Mint type.

</WithNotes>

<ScrollyCoding>

## !!steps

Create and fund a Kit client, then generate a signer to use as the address of
the new mint account. The client payer funds account creation and pays the
transaction fee.

```ts title="Client and mint setup"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
```

```ts !! title="Create mint account"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
  fetchMint,
  getInitializeMintInstruction,
  getMintSize,
  TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";

// !focus(1:12)
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
```

## !!steps

Calculate the mint account size in bytes, then make an RPC request to calculate
the lamports required to store that data in the account. This required balance
is referred to as rent.

```ts title="Mint account size and rent"
const space = BigInt(getMintSize());

const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();
```

```ts !! title="Create mint account"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
  fetchMint,
  getInitializeMintInstruction,
  getMintSize,
  TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();

// !focus(1:3)
const space = BigInt(getMintSize());

const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();
```

## !!steps

<WithMentions>

The first instruction invokes the System Program. The instruction uses the
[`payer`](mention:payer) to fund a [`newAccount`](mention:new-account),
allocates the mint account [`space`](mention:space), transfers the rent-exempt
[`lamports`](mention:lamports), and assigns ownership to the
[`programAddress`](mention:program-address).

```ts title="Create account instruction"
const createAccountInstruction = getCreateAccountInstruction({
  // !mention payer
  payer: client.payer,
  // !mention new-account
  newAccount: mint,
  // !mention space
  space,
  // !mention lamports
  lamports: rent,
  // !mention program-address
  programAddress: TOKEN_2022_PROGRAM_ADDRESS
});
```

</WithMentions>

```ts !! title="Create mint account"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
  fetchMint,
  getInitializeMintInstruction,
  getMintSize,
  TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();

const space = BigInt(getMintSize());

const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();

// !focus(1:7)
const createAccountInstruction = getCreateAccountInstruction({
  payer: client.payer,
  newAccount: mint,
  space,
  lamports: rent,
  programAddress: TOKEN_2022_PROGRAM_ADDRESS
});
```

## !!steps

<WithMentions>

The second instruction invokes the Token Extensions Program. The instruction
initializes the [`mint`](mention:mint-account) address with a
[`decimals`](mention:decimals) value, a
[`mintAuthority`](mention:mint-authority), a
[`freezeAuthority`](mention:freeze-authority), and specifies the
[`tokenProgram`](mention:token-program) that owns the mint account.

```ts title="Initialize mint instruction"
const initializeMintInstruction = getInitializeMintInstruction({
  // !mention mint-account
  mint: mint.address,
  // !mention decimals
  decimals: 2,
  // !mention mint-authority
  mintAuthority: client.payer.address,
  // !mention freeze-authority
  freezeAuthority: client.payer.address,
  // !mention token-program
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
```

</WithMentions>

```ts !! title="Create mint account"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
  fetchMint,
  getInitializeMintInstruction,
  getMintSize,
  TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();

const space = BigInt(getMintSize());

const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();

const createAccountInstruction = getCreateAccountInstruction({
  payer: client.payer,
  newAccount: mint,
  space,
  lamports: rent,
  programAddress: TOKEN_2022_PROGRAM_ADDRESS
});

// !focus(1:7)
const initializeMintInstruction = getInitializeMintInstruction({
  mint: mint.address,
  decimals: 2,
  mintAuthority: client.payer.address,
  freezeAuthority: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
```

## !!steps

Send both instructions in one transaction. The create account instruction must
come before the initialize mint instruction because the mint account must exist
before the Token Extensions Program can write mint data to the account.

```ts title="Send transaction"
const result = await client.sendTransaction([
  createAccountInstruction,
  initializeMintInstruction
]);
```

```ts !! title="Create mint account"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
  fetchMint,
  getInitializeMintInstruction,
  getMintSize,
  TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();

const space = BigInt(getMintSize());

const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();

const createAccountInstruction = getCreateAccountInstruction({
  payer: client.payer,
  newAccount: mint,
  space,
  lamports: rent,
  programAddress: TOKEN_2022_PROGRAM_ADDRESS
});

const initializeMintInstruction = getInitializeMintInstruction({
  mint: mint.address,
  decimals: 2,
  mintAuthority: client.payer.address,
  freezeAuthority: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

// !focus(1:4)
const result = await client.sendTransaction([
  createAccountInstruction,
  initializeMintInstruction
]);

console.log("Mint Address:", mint.address);
console.log("Transaction Signature:", result.context.signature);
```

## !!steps

After the transaction is confirmed, fetch the mint account.

```ts title="Fetch mint account"
const mintAccount = await fetchMint(client.rpc, mint.address);
console.log("Mint Account:", mintAccount);
```

```ts !! title="Create mint account"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
  fetchMint,
  getInitializeMintInstruction,
  getMintSize,
  TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();

const space = BigInt(getMintSize());

const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();

const createAccountInstruction = getCreateAccountInstruction({
  payer: client.payer,
  newAccount: mint,
  space,
  lamports: rent,
  programAddress: TOKEN_2022_PROGRAM_ADDRESS
});

const initializeMintInstruction = getInitializeMintInstruction({
  mint: mint.address,
  decimals: 2,
  mintAuthority: client.payer.address,
  freezeAuthority: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const result = await client.sendTransaction([
  createAccountInstruction,
  initializeMintInstruction
]);

console.log("Mint Address:", mint.address);
console.log("Transaction Signature:", result.context.signature);

// !focus(1:2)
const mintAccount = await fetchMint(client.rpc, mint.address);
console.log("Mint Account:", mintAccount);
```

</ScrollyCoding>

<Callout type="info">
  These examples use `generatedPayer()` to create a throwaway keypair for local
  testing. Production applications should never hold raw private keys in code —
  delegate signing to a key-management backend. See [Signing in
  Production](/docs/core/transactions/signing-in-production).
</Callout>
