How to Generate an Ethereum Address in JavaScript, Python and Go

An Ethereum address is derived from a private key, and you can create one in a few lines of code without a website, browser extension, or hosted service. The private key comes from a secure random source, and the address is a deterministic result of that key. So a self-written ethereum address generator runs entirely on your machine and never sends anything over the network.

This guide shows the derivation step by step, then gives working code in three stacks: JavaScript with ethers.js and viem, Python with eth-account, and Go with go-ethereum. All of them do the same cryptography under the hood.

One thing to keep in mind before you start: the private key is the only real secret. Whoever holds it controls any funds the address receives, so where you generate and store it matters more than which language you pick.

What Is an Ethereum Address?

An Ethereum address is a 42-character string that starts with 0x, followed by 40 hexadecimal characters — for example, 0x742d35Cc6634C0532925a3b844Bc454e4438f44e. Those 40 characters represent 20 bytes of data. It’s the public identifier you share to receive ETH or tokens.

The same format is used by two different things: externally owned accounts (EOAs), controlled by a private key, and contract accounts, controlled by deployed code. A freshly generated address is always an EOA. A contract address only appears when someone deploys a contract, and it’s calculated from the deployer’s address and nonce rather than from a private key.

Every EVM-compatible network — Ethereum, BNB Smart Chain, Polygon, Arbitrum, and others — uses this address format, because they share the same account model.

Why Not Just Use an Online Address Generator?

Plenty of websites offer to create a key pair for you in the browser. The problem is trust. The moment a page shows you a private key, you have to assume it could have been logged, transmitted, or stored somewhere you can’t see.

Generating locally removes that doubt. The code runs on hardware you control, the private key stays in memory (or a file you chose), and nothing touches a remote server. For anything holding real value, that difference is the whole point.

The catch is that local generation puts responsibility on you. There’s no “forgot password” link — lose the key and the funds are gone. That trade-off is why developers automate generation inside systems that also handle secure storage.

Who Generates Ethereum Addresses Programmatically?

Creating addresses in code is a routine task across several kinds of software:

  • Wallet apps that spin up a new account when a user signs up or adds a wallet.
  • Backends and payment systems that assign a unique deposit address per user or per invoice.
  • Exchanges and custodians that provision addresses at scale behind key-management infrastructure.
  • Developers and testers who need throwaway accounts for testnets, local forks, or CI pipelines.
  • Bots and automation that manage one or more accounts without a human clicking through a wallet UI.

In each case the generation itself is cheap and offline. The engineering effort goes into protecting and organizing the keys afterward.

How Is an Ethereum Address Created?

An address is the end of a short, deterministic pipeline. The only random part is the first step; everything after it is pure math, so the same private key always produces the same address.

  1. Generate a private key. Pick a random 256-bit (32-byte) number from a cryptographically secure source, within the valid range of the secp256k1 curve. Secp256k1 is the elliptic curve Ethereum and Bitcoin both use for keys and signatures.
  2. Derive the public key. Run the private key through ECDSA (Elliptic Curve Digital Signature Algorithm) on secp256k1. This gives a 64-byte public key.
  3. Hash the public key. Apply Keccak-256 to those 64 bytes. Keccak-256 is the hash function Ethereum uses; it predates and differs slightly from the final NIST SHA-3 standard.
  4. Take the last 20 bytes. The final 20 bytes of that hash, written in hex with a 0x prefix, are the address.
  5. Add a checksum. Re-case the hex letters according to EIP-55 so wallets can catch mistyped addresses.

You rarely write these steps by hand. The libraries below run all five for you, which is why the real question is which one fits your stack. Understanding the pipeline mostly tells you one thing: protect step one’s output, the private key.

Generating an Ethereum Address in JavaScript

For new JavaScript and TypeScript projects, the two maintained choices are ethers.js and viem. Note that web3.js is no longer an option for fresh code — ChainSafe archived the library on March 4, 2025, saying it was “time to pass the torch” to ethers and viem. The official ethereum.org JavaScript libraries page now points new projects to the same two.

Using ethers.js

In ethers v6, Wallet.createRandom() generates a key pair using a secure random source and returns the address, the private key, and a recovery mnemonic.

js

import { Wallet } from "ethers"; // ethers v6

const wallet = Wallet.createRandom();

console.log("Address:    ", wallet.address);
console.log("Private key:", wallet.privateKey);
console.log("Mnemonic:   ", wallet.mnemonic.phrase);

Install it with npm install ethers. The returned mnemonic.phrase is a 12-word backup you can import into most wallets, which makes ethers a good fit when you want a human-recoverable account rather than a bare key.

Using viem

Viem splits the job into two small functions from viem/accounts: generatePrivateKey() for the random key, and privateKeyToAccount() to derive the account object.

js

import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";

const privateKey = generatePrivateKey();      // 32 random bytes, 0x-prefixed
const account = privateKeyToAccount(privateKey);

console.log("Address:    ", account.address);
console.log("Private key:", privateKey);

Install it with npm install viem. Viem is TypeScript-first and tree-shakable, so it tends to produce smaller bundles, and it uses the audited @noble/curves library for the elliptic-curve math.

Generating an Ethereum Address in Python

On the Python side, eth-account is the standard library — it’s the same package web3.py relies on for signing. Account.create() makes a new key and returns a LocalAccount object.

python

from eth_account import Account

acct = Account.create()

print("Address:    ", acct.address)
print("Private key:", acct.key.hex())

Install it with pip install eth-account. The address property is already EIP-55 checksummed, and key holds the raw private key as bytes. Account.create() draws randomness from the operating system’s secure generator; you can pass extra entropy, but it isn’t required for a secure key.

If you later need a mnemonic-based account, eth-account supports that too, though it’s behind an explicit opt-in (Account.enable_unaudited_hdwallet_features()) because the feature is marked unaudited.

Generating an Ethereum Address in Go

In Go, the reference implementation lives in the go-ethereum crypto package, the same codebase that powers the Geth client. Here you see the derivation a little more directly: generate a key, extract the public key, then convert it to an address.

go

package main

import (
    "crypto/ecdsa"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common/hexutil"
    "github.com/ethereum/go-ethereum/crypto"
)

func main() {
    privateKey, err := crypto.GenerateKey()
    if err != nil {
        log.Fatal(err)
    }

    privateKeyBytes := crypto.FromECDSA(privateKey)
    fmt.Println("Private key:", hexutil.Encode(privateKeyBytes))

    publicKeyECDSA, ok := privateKey.Public().(*ecdsa.PublicKey)
    if !ok {
        log.Fatal("could not cast public key to ECDSA")
    }

    address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
    fmt.Println("Address:    ", address)
}

Install it with go get github.com/ethereum/go-ethereum. GenerateKey() uses secp256k1 and Go’s crypto/rand, and PubkeyToAddress() runs the Keccak-256 hash and takes the last 20 bytes. One thing to weigh: importing go-ethereum pulls in a large module, which is fine for a node or backend but heavy if all you want is key generation.

Which Language and Library Should You Use?

All four options produce a valid address from secure randomness. The right one is usually whatever matches the rest of your codebase.

LanguageLibraryInstallGenerate callNotes
JavaScript / TSethers.js v6npm install ethersWallet.createRandom()Returns address, key, and a 12-word mnemonic
JavaScript / TSviemnpm install viemgeneratePrivateKey() + privateKeyToAccount()Smaller bundles, TypeScript-first, uses @noble/curves
Pythoneth-accountpip install eth-accountAccount.create()Same library web3.py signs with
Gogo-ethereumgo get github.com/ethereum/go-ethereumcrypto.GenerateKey() + crypto.PubkeyToAddress()Exposes each derivation step; heavy dependency

A quick way to decide: reach for ethers.js if you want a recoverable wallet with minimal code, viem if you care about bundle size and modern TypeScript, eth-account if your backend already runs web3.py, and go-ethereum if you’re building in Go and can absorb the dependency.

How Do You Check a New Address or Send From It?

A newly generated address starts empty. It has no balance and no transaction history, and it isn’t “registered” anywhere — it quietly comes into existence on-chain the first time someone sends funds to it. There’s no gas cost or setup to create the address itself.

To read its balance or broadcast a transaction, your code has to talk to an Ethereum node through an RPC (Remote Procedure Call) endpoint. Reading a balance uses the JSON-RPC method eth_getBalance:

bash

curl YOUR_ETHEREUM_RPC_URL \
  -X POST -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["0xYourAddress","latest"]}'

Running your own Ethereum node to serve that request means syncing and maintaining the client yourself. A managed provider like NOWNodes gives you an Ethereum RPC endpoint so your generator, wallet, or backend can call eth_getBalance, submit signed transactions, and read chain state without hosting infrastructure. The same endpoint works for both mainnet and the testnets you’d use while developing.

How to Keep the Private Key Safe

Generation is the easy part. Key handling is where addresses are actually lost or stolen, so a few rules matter more than any code above.

  • Treat the private key as the master credential. Anyone who reads it can move the funds. Never paste it into a website, log it, or hardcode it in a repository.
  • Trust the library’s randomness. The generators here use cryptographically secure sources. Never swap in a general-purpose random function such as JavaScript’s Math.random(), which is predictable.
  • Encrypt keys at rest. For anything beyond a throwaway test key, store an encrypted keystore or use a secrets manager, a KMS, or a hardware wallet rather than a plaintext file.
  • Back up what you can’t recover. If you generated a mnemonic, store it offline and separately. There is no reset path for a lost key.

None of this is financial advice, but it’s the baseline for not losing an account the moment it holds something worth taking.

Conclusion

Generating an Ethereum address comes down to two things: a private key from a secure random source, and a fixed sequence of elliptic-curve math and Keccak-256 hashing that turns that key into an address. Every library here — ethers.js, viem, eth-account, and go-ethereum — runs that pipeline for you, so the choice is about your stack, not the cryptography.

Pick the library that matches the code you already write, keep the private key protected, and connect to an RPC endpoint when you need to check balances or send transactions. With those pieces in place, your own ethereum address generator is a small, dependable building block rather than a security liability.

FAQ

Is an Ethereum address the same on other EVM chains like BNB Smart Chain or Polygon?

Yes. Because EVM networks share the same key-to-address derivation, one generated address is valid on Ethereum, BNB Smart Chain, Polygon, and other EVM chains. The balances and transaction history are separate per chain, but the address string itself is identical.

Can two people ever generate the same Ethereum address?

In practice, no. The address space is roughly 2^160, which is large enough that a collision from secure random generation is considered statistically impossible. This only holds if the private key came from a proper random source.

What’s the difference between a private key and a seed phrase?

A private key is a single 32-byte number that controls one account. A seed phrase (or mnemonic) is a set of 12 to 24 words that can deterministically generate many private keys, following standards like BIP-39. Tools such as ethers.js and eth-account can produce a mnemonic alongside the key so the account is easier to back up and restore.

Why do some Ethereum addresses mix uppercase and lowercase letters?

The mixed casing is a checksum defined in EIP-55. The letters in a lowercase address are selectively capitalized based on a hash of the address, so wallets can detect a mistyped character before sending funds. An all-lowercase address is still technically valid, but the checksummed form is safer to share.