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