A high-performance URL shortening service built with Go, PostgreSQL, and Redis. GoShort converts long URLs into compact, memorable short links while maintaining fast redirects through intelligent caching.
- Features
- Architecture
- Project Structure
- Tech Stack
- Setup & Installation
- Configuration
- API Endpoints
- How It Works
- Core Components
✨ Key Features:
- URL Shortening: Convert long URLs into compact, base62-encoded short links
- Redis Caching: Lightning-fast redirects with in-memory caching layer
- PostgreSQL Storage: Persistent, reliable storage for all shortened URLs
- Health Checks: Built-in health endpoint for monitoring
- Efficient Encoding: Uses base62 encoding for human-readable short codes
- Automatic Cache Population: Smart caching strategy that learns from access patterns
GoShort follows a layered architecture pattern:
┌─────────────────────────────────────────┐
│ HTTP Request Handler │
│ (Standard Go http.ServeMux) │
└──────────────┬──────────────────────────┘
│
┌───────┴────────┐
│ │
┌───▼────┐ ┌───▼───────┐
│ Routes │ │ Handlers │
└────────┘ └───┬───────┘
│
┌───────────┼───────────┐
│ │ │
┌────▼──┐ ┌───▼────┐ ┌──▼────┐
│ Redis │ │ Models │ │Config │
│ Cache │ │ │ │ (DB) │
└───────┘ └────────┘ └────────┘
│
┌────▼─────────────┐
│ PostgreSQL DB │
│ (Long-term │
│ storage) │
└──────────────────┘
GoShort/
├── cmd/
│ └── main.go # Application entry point
├── internal/
│ ├── config/
│ │ ├── postgre.go # PostgreSQL connection & initialization
│ │ └── redis.go # Redis connection & initialization
│ ├── handlers/
│ │ └── routeHandlers.go # HTTP request handlers (shorten & redirect)
│ ├── models/
│ │ └── model.go # Data models (currently minimal)
│ └── routes/
│ └── routes.go # Route definitions & multiplexing
├── pkg/
│ └── utils/
│ └── base62.go # Base62 encoding utility
└── go.mod # Go module definition & dependencies
- cmd/: Contains the application entry point (
main.go) that initializes the server - internal/: Private packages used only within this application
- config/: Database and cache connection management
- handlers/: Business logic for handling HTTP requests
- models/: Data structures and models
- routes/: Route registration and request multiplexing
- pkg/: Reusable packages that could potentially be imported by other projects
- utils/: Helper functions (base62 encoding)
| Technology | Version | Purpose |
|---|---|---|
| Go | 1.26.2 | Core language |
| PostgreSQL | Via lib/pq |
Primary data storage |
| Redis | Via go-redis/v9 |
Caching layer |
| godotenv | 1.5.1 | Environment variable management |
| xxhash | 2.3.0 | Fast hashing (indirect dependency) |
github.com/joho/godotenv v1.5.1 // Load .env files for configuration
github.com/lib/pq v1.12.3 // PostgreSQL driver
github.com/redis/go-redis/v9 v9.19.0 // Redis client library- Go 1.26.2 or higher
- PostgreSQL database instance
- Redis instance (local or cloud-based like Upstash)
git clone https://github.com/V3DxNT/GoShort.git
cd GoShort
go mod downloadCreate a PostgreSQL database with the following schema:
CREATE TABLE urls (
id SERIAL PRIMARY KEY,
long_url VARCHAR(2048) NOT NULL,
short_code VARCHAR(20) UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Optional: Create an index on short_code for faster lookups
CREATE INDEX idx_short_code ON urls(short_code);Create a .env file in the root directory:
# PostgreSQL Configuration
DATABASE_URL=postgresql://username:password@localhost:5432/goshort
# Redis Configuration
REDIS_URL=redis://default:password@host:port
# Server Configuration
PORT=7777go run cmd/main.goThe server will start on the specified PORT (default: 7777) and output:
Connected to DB
Connected to Redis
Listening on port 7777
| Variable | Description | Default | Required |
|---|---|---|---|
DATABASE_URL |
PostgreSQL connection string | - | ✅ Yes |
REDIS_URL |
Redis connection URL | - | ✅ Yes |
PORT |
Server port | 7777 |
❌ No |
PostgreSQL (postgre.go):
- Uses standard Go
database/sqlpackage withpqdriver sql.Open()initializes the connection pool (doesn't connect immediately)DB.Ping()performs actual TCP connection verification- Supports any PostgreSQL instance (local, remote, cloud-hosted)
Redis (redis.go):
- Connects via URL parsing (supports Upstash or self-hosted Redis)
- No localhost fallback - requires explicit Redis URL
- Uses context for connection lifecycle management
- Implements
PINGfor connection verification
Endpoint: POST /api/shorten
Request:
{
"url": "https://example.com/very/long/url/that/is/hard/to/remember"
}Response (Success 200):
{
"url": "https://localhost:7777/abc123"
}Response (Error 400):
Bad Request - Invalid JSON format
Response (Error 500):
Internal Server Error - Database issue
Endpoint: GET /{short_code}
Behavior:
- Checks Redis cache first (instant, if available)
- Falls back to PostgreSQL if not cached
- Caches result in Redis for future requests
- Redirects (HTTP 302) to original long URL
Example:
- Request:
GET /abc123 - Response: HTTP 302 redirect to
https://example.com/very/long/url/...
Endpoint: GET /health
Response (200):
GoShort IS LIVE
Endpoint: GET /
Response:
🚀 GoShort IS LIVE & READY!
1. User sends POST /api/shorten with long URL
↓
2. Handler receives and validates JSON
↓
3. Insert long_url into PostgreSQL → returns auto-generated ID
↓
4. Encode ID using Base62 algorithm → generates short_code
↓
5. Update URL record with short_code in PostgreSQL
↓
6. Cache short_code → long_url mapping in Redis
↓
7. Return shortened URL to user
1. User requests GET /{short_code}
↓
2. Check Redis cache for short_code
├─ HIT: Redirect immediately (fast path)
├─ MISS: Query PostgreSQL
│ ├─ FOUND: Cache result + redirect
│ └─ NOT FOUND: Return 404
└─ ERROR: Return 500 Redis error
The Base62Encode() function converts database IDs into human-readable short codes:
Algorithm:
- Takes unsigned 64-bit integer (database ID)
- Iteratively divides by 62, collecting remainders
- Maps remainders to alphabet:
[a-z][A-Z][0-9] - Reverses the result to get final short code
Example:
- ID: 12345 → Short Code:
"3kd" - ID: 1000000 → Short Code:
"4c92"
Advantages:
- Compact representation (62 possible characters)
- Deterministic & reversible
- No external API calls needed
- Human-readable (includes letters and numbers)
Responsibilities:
- Load environment variables from
.env - Initialize PostgreSQL connection
- Initialize Redis connection
- Create HTTP request multiplexer
- Register all routes
- Start HTTP server on configured port
Key Functions:
func main()
└─ godotenv.Load() // Load .env configuration
└─ config.ConnectDb() // Connect to PostgreSQL
└─ config.ConnectRedis() // Connect to Redis
└─ routes.HandleRoutes() // Register API routes
└─ http.ListenAndServe() // Start serverContains:
URLRequest: Struct for incoming POST requestsCreateShortURL(): Handler forPOST /api/shortenRedirectURL(): Handler forGET /{short_code}andGET /
CreateShortURL Process:
- Decode JSON request body
- Insert long_url into database (auto-generate ID)
- Encode ID using Base62
- Update database with short_code
- Cache mapping in Redis
- Return shortened URL
RedirectURL Process:
- Extract short_code from URL path
- Try Redis cache first
- Fall back to database query
- Cache result if found
- Redirect or return error
Global Variable:
var DB *sql.DB // Connection poolFunction: ConnectDb()
- Reads
DATABASE_URLenvironment variable - Opens PostgreSQL connection pool with
sql.Open() - Performs actual connection with
DB.Ping() - Panics if connection fails
Key Concepts:
sql.Open()doesn't establish a connection, just initializes the poolDB.Ping()performs actual TCP socket connection over the network- Supports localhost or remote PostgreSQL instances
Global Variable:
var Cache *redis.Client // Redis connectionFunction: ConnectRedis()
- Reads
REDIS_URLenvironment variable - Parses URL to extract connection parameters
- Creates Redis client instance
- Verifies connection with
Ping() - Panics if connection fails
Important Notes:
- No localhost fallback - must provide valid REDIS_URL
- Designed for cloud Redis services (like Upstash)
- Uses
context.Background()for connection management - Context is Go's way of managing lifespans and cancellation signals
Function: HandleRoutes()
- Registers HTTP route handlers with multiplexer
- Routes:
POST /api/shorten→handlers.CreateShortURLGET /→handlers.RedirectURL
Function: Base62Encode(num uint64) string
Algorithm:
Input: 12345 (uint64)
↓
Alphabet: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
↓
Iterative Division by 62:
12345 % 62 = 35 → 'z'
199 % 62 = 13 → 'n'
3 % 62 = 3 → 'd'
↓
Reverse: ['z','n','d'] → "dnz"
↓
Output: "dnz"
- Redis TTL: Set to
0(never expires) for persistent caching - Cache Population: Automatic on first access to any URL
- Cache Hit Rate: Improves with repeated access patterns
- Add index on
short_codecolumn for O(1) lookups - Consider partitioning for massive scale (millions of URLs)
- Stateless handlers allow horizontal scaling
- Database becomes bottleneck at scale (sharding recommended)
- Redis cluster mode for distributed caching
Potential improvements for production deployment:
- URL validation before shortening
- Custom short code support
- Analytics (click tracking, timestamps)
- API authentication & rate limiting
- URL expiration TTL
- Bulk URL shortening
- QR code generation
- Link preview metadata
- Admin dashboard
- Prometheus metrics integration
V3DxNT - GitHub Profile
This project is open source. Modify and use as needed.
| Task | Command |
|---|---|
| Download dependencies | go mod download |
| Run application | go run cmd/main.go |
| Build binary | go build -o goshort cmd/main.go |
| Check dependencies | go mod graph |
Last Updated: June 2026 Status: ✅ Active Development