A lightweight URL shortener built with Go and PostgreSQL. Submit a long URL, get an 8-character short code, and redirect visitors to the original link.
- Shorten URLs via a JSON REST API
- Redirect short codes to the original URL with sub-15ms latency
- IP-based Token Bucket Rate Limiting (20 req/s, 40 burst) with automated memory cleanup
- JWT Authentication & Secure Session Management
- Real-time click attribution & link analytics
- Persistent storage with PostgreSQL 16
- Automatic database migrations on startup
- Local development setup with Docker Compose & Air hot reload
| Layer | Technology |
|---|---|
| Language | Go 1.26 |
| HTTP | net/http (stdlib) |
| Database | PostgreSQL 16 |
| DB driver | pgx/v5 |
| Config | godotenv |
| Containers | Docker Compose |
url_shortner/
├── main.go # HTTP server, handlers, and URL logic
├── db_connect.go # Database connection and schema setup
├── docker-compose.yml # Local PostgreSQL container
├── go.mod
├── go.sum
└── .env # Local config (not committed)
- A client sends a
POST /shortenrequest with a long URL. - The server hashes the URL with MD5 and takes the first 8 hex characters as the short code.
- The mapping is stored in PostgreSQL.
- Visiting
GET /redirect/{code}looks up the original URL and returns an HTTP 302 redirect.
git clone https://github.com/log1-codes/url_shortner.git
cd url_shortnerdocker compose up -dThis starts a PostgreSQL 16 container with:
| Setting | Value |
|---|---|
| User | urlshortner |
| Password | urlshortner |
| Database | urlshortner |
| Port | 5432 |
Data is persisted in a named Docker volume (postgres_data).
Create a .env file in the project root:
DATABASE_URL=postgres://urlshortner:urlshortner@localhost:5432/urlshortner
.envis listed in.gitignoreand should never be committed.
go mod downloadgo run .The server starts on port 3000. On startup it connects to PostgreSQL and creates the urls table if it does not exist.
GET /
Response: plain text
Anurag's go server
POST /shorten
Content-Type: application/json
Request body:
{
"url": "https://example.com/some/long/path"
}Success response (200 OK):
{
"short_url": "a1b2c3d4"
}Error responses:
| Status | Condition |
|---|---|
400 |
Invalid request body |
500 |
Database insert failed |
Example:
curl -X POST http://localhost:3000/shorten \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}'GET /redirect/{short_code}
Success: 302 Found redirect to the original URL.
Error responses:
| Status | Condition |
|---|---|
404 |
Short code not found |
Example:
curl -L http://localhost:3000/redirect/a1b2c3d4The urls table is created automatically in db_connect.go:
CREATE TABLE IF NOT EXISTS urls (
id TEXT PRIMARY KEY,
original_url TEXT NOT NULL,
short_url TEXT NOT NULL,
creation_date TIMESTAMPTZ NOT NULL DEFAULT NOW()
);| Column | Description |
|---|---|
id |
Short code (same as short_url) |
original_url |
The full URL submitted by the client |
short_url |
8-character MD5 hash prefix |
creation_date |
Timestamp when the URL was shortened |
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string |
Example:
postgres://<user>:<password>@<host>:<port>/<database>
# Start PostgreSQL in the background
docker compose up -d
# View logs
docker compose logs -f postgres
# Stop the container
docker compose down
# Stop and remove persisted data
docker compose down -vCompile a binary:
go build -o url-shortner .
./url-shortner- Short codes are derived from an MD5 hash of the URL. Submitting the same URL twice will fail with a primary key conflict.
- No input validation on URL format.
- No authentication or rate limiting.
- Uses a single database connection rather than a connection pool.
MIT