Perfect — here are 10 Go mini-projects focused ONLY on general programming, no web, no APIs, no backend.
These improve pure Go skills: data structures, concurrency, file handling, algorithms, CLI tools, etc
1. Random Password Generator (Done)
Skills: strings, randomness, slices, crypto/rand, functions.
2. Text File Word Counter
Read a .txt file and print:
- total words
- total lines
- most common word
Skills: file reading (os, bufio), maps, string processing, counting algorithms.
3. Simple CLI Calculator
Accept command-line input:go run main.go add 10 3
Supports: add, subtract, multiply, divide.
Skills: CLI arguments (os.Args), parsing, error handling.
4. Contact Book (Stored in JSON File) Features:
- Add contact
- List contacts
- Delete contact
Save everything in contacts.json.
Skills: JSON, structs, file I/O, slices.
5. Todo App in Terminal (Persistent)
Store tasks in a JSON or text file.
Commands: add, delete, list, mark-done.
Skills: file writing, slices, struct organization, CLI tools.
6. Concurrency Demo: Goroutine Timer: Create multiple timers that run in parallel.
Example:
- Timer 1 → prints every 2 seconds
- Timer 2 → prints every 5 seconds
Skills: goroutines, channels, time package.
7. Sudoku Solver (Backtracking Algorithm): Take a partially filled Sudoku board and solve it.
Skills: 2D arrays, recursion, backtracking, algorithm design.
8. File Encryption / Decryption Tool: Encrypt any text file using XOR or AES (basic version).
Skills: reading binary data, byte slices, basic crypto, command-line usage.
9. Markov Chain Text Generator
Feed a text file (like a book chapter) and generate random sentences like:
“The quick brown fox jumps inside the happy cloud…”
Skills: maps of slices, random selection, string building, algorithms.
10. Basic Image Manipulator (No GUI)
Load a PNG or JPEG and perform operations like:
- convert to grayscale
- flip horizontally
- resize (nearest neighbor)
Skills: Go’s image package, pixel manipulation, file I/O, loops.
Table of Contents
⭐ Skills You Build Across These Projects
| Skill | Projects That Teach It |
|---|---|
| File I/O | Word Counter, Contact Book, Todo App, Image Tools |
| JSON | Contact Book, Todo App |
| CLI tools | Calculator, Todo App |
| Concurrency | Goroutine Timer |
| Data structures | Sudoku Solver, Markov Generator |
| Algorithms | Sudoku Solver, Markov Generator |
| Slices & Maps | Most projects |
| Error handling | All projects |
| Crypto & security | Password Generator, File Encryption |
Random Password generator
package main
import ("crypto/rand" "fmt" "math/big")
const (
uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lowercase = "abcdefghijklmnopqrstuvwxyz"
digits = "0123456789"
symbols = "!@#$%^&*()-_=+[]{}|;:,.<>/?"
)
func randomChar(chars string) (byte, error) {
max := big.NewInt(int64(len(chars)))
n, err := rand.Int(rand.Reader, max)
if err != nil {
return 0, err
}
return chars[n.Int64()], nil
}
func strongPasswordGenerator(length int) (string, error) {
// Step 1 : Ensure at least one of each
password := make([]byte, 0, length)
sets := []string{uppercase, lowercase, digits, symbols}
for _, set := range sets {
ch, err := randomChar(set)
if err != nil {
return "", err
}
password = append(password, ch)
}
// Fill remaining characters
for len(password) < length {
ch, err := randomChar(allChars)
if err != nil {
return "", err
}
password = append(password, ch)
}
// Shuffle password
for i := range password {
jBig, err := rand.Int(rand.Reader, big.NewInt(int64(len(password))))
if err != nil {
return "", err
}
j := jBig.Int64()
password[i], password[j] = password[j], password[i]
}
return string(password), nil
}
func main() {
for {
var length int
fmt.Print("Enter the password length (min 10): ")
_, err := fmt.Scan(&length)
if err != nil {
fmt.Println("Please enter a valid number.")
continue
}
if length < 10 {
fmt.Println("Password must be at least 10 characters.")
continue
}
password, err := strongPasswordGenerator(length)
if err != nil {
fmt.Println("Error generating password:", err)
continue
}
fmt.Println("Generated Password:", password)
var choice string
fmt.Print("Generate another? (yes/no): ")
fmt.Scan(&choice)
if choice != "yes" && choice != "y" {
fmt.Println("Goodbye!")
break
}
}
}
Technical explaination on above code
Here’s a simple, clear explanation for these lines:
max := big.NewInt(int64(len(chars)))
n, err := rand.Int(rand.Reader, max)
✅ What this does
1. max := big.NewInt(int64(len(chars)))
len(chars)= how many characters are in the string.big.NewInt()converts that number into a big integer (required by crypto/rand).- This tells Go: “pick a number between 0 and len(chars)-1”.
Example:
If chars = "ABC"
Then len(chars) = 3
So:
max = 3 (meaning: pick 0, 1, or 2)
2. n, err := rand.Int(rand.Reader, max)
rand.Intgenerates a cryptographically secure random number.rand.Readeris a secure source of randomness provided by your OS.
In other words:
rand.Reader = strong, system-level randomness
(better than math/rand, which is predictable)
Example output:
If rand.Int(rand.Reader, 3) is called, possible values:
0
1
2
Each value is secure and unpredictable.
✔ If chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
This string has 26 characters.
1. What is max?
Since len(chars) = 26:
max = 26
👉 This means Go will generate a number in the range:
0 to 25 (inclusive)
✔ What is n?
n, err := rand.Int(rand.Reader, max)
This line generates a secure random integer from:
0 to 25
Examples of possible values of n:
0
13
25
7
Every run gives a different unpredictable value.
✔ Is n a character?
No — n is NOT a character. n is a random index number. Then we use it to pick a character:
chars[n.Int64()]
Example If:
n = 0 → chars[0] = 'A'
n = 5 → chars[5] = 'F'
n = 25 → chars[25] = 'Z'
So the random character comes from:
random index → used to pick a letter
✔ Summary
| Variable | Meaning |
|---|---|
max = 26 | Size of allowed range |
n | Secure random number from 0–25 |
chars[n] | Random character from A to Z |
✅ What is rand.Reader (in simple words)
rand.Reader is Go’s built-in source of secure random bytes. Think of it like this:
🔐 rand.Reader = a pipe connected to your operating system’s secure randomness
Your OS constantly generates high-quality random data (mouse movement, CPU noise, hardware RNG, etc.). Go exposes this through:
rand.Reader
It’s the trusted source of randomness used in:
- password generators
- encryption
- tokens
- keys
- anything security-related
🤔 Why have I not seen this in other languages?
Because most languages hide this behind a single function:
| Language | Secure random function |
|---|---|
| Python | secrets.token_bytes() |
| JavaScript | crypto.getRandomValues() |
| Rust | OsRng |
| Java | SecureRandom |
| C# | RNGCryptoServiceProvider |
They also use the OS’s secure randomness—just not as obviously. Go chooses to show it explicitly:
rand.Reader // ← secure random source
This gives the developer more control and makes it clear that the randomness is cryptographically secure.
✔ Why do we need rand.Reader?
Because math/rand is predictable, meaning:
❌ It can be guessed
❌ It can be repeated
❌ It is unsafe for passwords or keys
But:
✔ crypto/rand (with rand.Reader) produces randomness that cannot be predicted.
Example:
rand.Int(rand.Reader, max)
This tells Go:
“Use secure randomness to generate a number from 0 to max-1.”
📌 Simple Analogy
- math/rand = dice in your hand (predictable)
- rand.Reader = casino-grade dice machine (unpredictable, safe)
For passwords, keys, tokens → you need the casino machine.
✔ Tiny example
b := make([]byte, 5)
rand.Reader.Read(b)
fmt.Println(b)
This prints 5 secure random bytes (different every time