Skip to Content
Technology Stack

Source: Jolli-sample-repos/url-shortener  Last Updated: 4/8/2026


Technology Stack

Detailed information about the technologies, libraries, and tools used in the URL Shortener project.

Backend Technologies

Node.js

Version: 16.x or higher

Why Node.js?

  • JavaScript ecosystem (same language as frontend)
  • Non-blocking I/O ideal for I/O-heavy operations
  • Large npm ecosystem
  • Active community and support
  • Excellent for REST APIs

Used For:

  • Runtime environment for backend server
  • Package management via npm

TypeScript

Version: 5.3.3

Why TypeScript?

  • Static type checking catches errors early
  • Better IDE support (autocomplete, refactoring)
  • Improved code documentation
  • Easier maintenance and refactoring
  • Gradual adoption (can mix with JavaScript)

Configuration: backend/tsconfig.json

{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "outDir": "./dist", "strict": true, "esModuleInterop": true } }

Key Features Used:

  • Strict mode for maximum type safety
  • Interface definitions for data models
  • Type inference
  • Optional chaining

Express.js

Version: 4.18.2

GitHub: https://github.com/expressjs/express 

Why Express?

  • De facto standard for Node.js web applications
  • Minimal and unopinionated
  • Robust routing
  • Middleware ecosystem
  • Excellent documentation

Used For:

  • HTTP server
  • Route handling
  • Middleware pipeline
  • Request/response handling

Key Middleware:

app.use(cors()); // Cross-origin requests app.use(express.json()); // JSON body parsing app.use(express.urlencoded({ extended: true })); // URL-encoded parsing

nanoid

Version: 3.3.7

GitHub: https://github.com/ai/nanoid 

Why nanoid?

  • Small footprint (130 bytes)
  • Cryptographically secure
  • Fast performance
  • URL-safe alphabet
  • Customizable length and alphabet

Used For:

  • Generating unique short codes

Implementation:

import { customAlphabet } from 'nanoid'; const ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; const nanoid = customAlphabet(ALPHABET, 6); const shortCode = nanoid(); // e.g., "AbC123"

Comparison to Alternatives:

LibraryLengthURL-SafeSecureSize
nanoid6-21YesYes130 bytes
uuid36NoYes3KB
shortid7-14YesNo8KB

Zod

Version: 3.22.4

GitHub: https://github.com/colinhacks/zod 

Why Zod?

  • TypeScript-first schema validation
  • Runtime type checking
  • Automatic type inference
  • Composable and reusable schemas
  • Excellent error messages

Used For:

  • Request body validation
  • Data sanitization
  • Type safety at runtime

Example Schema:

export const createUrlSchema = z.object({ longUrl: z.string().url({ message: 'Must be a valid URL' }), customCode: z .string() .regex(/^[a-zA-Z0-9]+$/, 'Must be alphanumeric') .min(4, 'Minimum 4 characters') .max(20, 'Maximum 20 characters') .optional(), expiresAt: z.string().datetime().optional(), });

Benefits:

  • Validation errors include field-specific messages
  • Types automatically inferred from schemas
  • Prevents invalid data from entering the system

Swagger/OpenAPI

Packages:

  • swagger-jsdoc (6.2.8) - Generate OpenAPI spec from JSDoc
  • swagger-ui-express (5.0.0) - Serve Swagger UI

Why Swagger?

  • Interactive API documentation
  • Try-it-out functionality
  • Standard OpenAPI 3.0 format
  • Auto-generated from code comments
  • Client SDK generation support

Used For:

  • API documentation at /api-docs
  • Testing endpoints interactively

Configuration: backend/src/swagger.ts

Example Route Documentation:

/** * @openapi * /api/v1/urls: * post: * summary: Create a short URL * tags: [URLs] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * longUrl: * type: string * format: uri */

CORS

Package: cors (2.8.5)

Why CORS?

  • Enable cross-origin requests from frontend
  • Required for separate frontend/backend deployments
  • Configurable origin whitelist

Used For:

  • Allowing frontend (different origin) to call backend API

Configuration:

// Development - allow all origins app.use(cors()); // Production - restrict to specific origins app.use(cors({ origin: ['https://yourfrontend.com'], credentials: true }));

Development Dependencies

nodemon

Version: 3.0.2

Why nodemon?

  • Auto-restart on file changes
  • Faster development workflow
  • Configurable watch patterns

Used For:

  • Development server with hot reload

Usage:

npm run dev # Runs: nodemon src/index.ts

ts-node

Version: 10.9.2

Why ts-node?

  • Execute TypeScript directly without compilation
  • REPL support
  • Faster development iteration

Used For:

  • Running TypeScript files in development
  • Used by nodemon to execute TypeScript

Frontend Technologies

Vanilla JavaScript

Why No Framework?

  • Simplicity - no build process needed
  • Learning - demonstrates core concepts
  • Performance - minimal overhead
  • Deployment - serve static files directly

Used For:

  • DOM manipulation
  • Event handling
  • Fetch API calls

HTML5

Features Used:

  • Semantic elements (<header>, <main>, <footer>)
  • Form validation attributes
  • Modern input types

CSS3

Features Used:

  • CSS Grid for layout
  • Flexbox for component alignment
  • CSS Variables for theming
  • Media queries for responsive design
  • Transitions for smooth interactions

No Preprocessor: Plain CSS for simplicity

Data Storage

In-Memory Storage

Implementation: JavaScript Map objects

Why Maps?

  • O(1) lookup time
  • Key-value storage
  • Better than plain objects for dynamic keys
  • Iteration support

Structure:

class UrlStorage { private urls: Map<string, ShortUrl> = new Map(); private longUrlIndex: Map<string, string> = new Map(); }

Limitations:

  • Data lost on server restart
  • Limited by available RAM
  • No persistence
  • Single-server only (no distributed storage)

Future Considerations:

PostgreSQL

  • Relational database
  • ACID compliance
  • Complex queries
  • Strong consistency

MongoDB

  • Document database
  • Flexible schema
  • Horizontal scaling
  • Good for JSON-like data

Redis

  • In-memory cache
  • Sub-millisecond latency
  • Perfect for URL lookups
  • Persistence options available

API Standards

REST Architecture

Principles Followed:

  • Stateless communication
  • Resource-based URLs
  • Standard HTTP methods
  • JSON for data exchange
  • Appropriate status codes

HTTP Methods:

  • GET - Retrieve resources
  • POST - Create resources
  • PUT - Update resources
  • DELETE - Remove resources

JSON

Why JSON?

  • Native JavaScript support
  • Human-readable
  • Widely supported
  • Compact format

Content-Type: application/json

Example Response:

{ "shortCode": "AbC123", "longUrl": "https://example.com", "createdAt": "2024-01-01T12:00:00.000Z", "clicks": 5 }

Build Tools

npm

Version: 7.x or higher

Used For:

  • Package management
  • Script running
  • Dependency resolution

Key Scripts:

{ "scripts": { "dev": "nodemon src/index.ts", "build": "tsc", "start": "node dist/index.js" } }

TypeScript Compiler (tsc)

Used For:

  • Compiling TypeScript to JavaScript
  • Type checking
  • Generating declaration files

Build Output: dist/ directory

Testing (Future)

While not currently implemented, recommended testing stack:

Unit Testing

  • Jest - Testing framework
  • ts-jest - TypeScript integration
  • supertest - HTTP assertions

Integration Testing

  • Supertest - API endpoint testing
  • Jest - Test runner

Example Test Structure:

describe('POST /api/v1/urls', () => { it('should create a short URL', async () => { const response = await request(app) .post('/api/v1/urls') .send({ longUrl: 'https://example.com' }); expect(response.status).toBe(201); expect(response.body.shortCode).toBeDefined(); }); });

ESLint

  • JavaScript/TypeScript linting
  • Code style enforcement
  • Best practices

Prettier

  • Code formatting
  • Consistent style
  • Auto-fixing

Husky

  • Git hooks
  • Pre-commit checks
  • Pre-push testing

Documentation Tools

Docusaurus

Version: 3.x

Why Docusaurus?

  • Built for documentation sites
  • React-based
  • Markdown support
  • Search functionality
  • Versioning support

Used For:

  • This documentation site

Location: aidan-doc/

JSDoc

Used For:

  • Inline code documentation
  • Swagger/OpenAPI generation
  • Type hints in JavaScript

Development Environment

Visual Studio Code

Extensions:

  • TypeScript support (built-in)
  • ESLint
  • Prettier
  • Thunder Client (API testing)
  • REST Client

Node Version Management

nvm (Node Version Manager)

  • Switch between Node.js versions
  • Project-specific versions
nvm install 18 nvm use 18

Production Considerations

Process Management

  • PM2 - Process manager
  • Docker - Containerization
  • Kubernetes - Orchestration

Monitoring

  • Winston - Logging
  • Prometheus - Metrics
  • Grafana - Visualization

Performance

  • Redis - Caching layer
  • nginx - Reverse proxy
  • CDN - Static asset delivery

Package Versions

Backend Dependencies:

{ "express": "^4.18.2", "nanoid": "^3.3.7", "zod": "^3.22.4", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.0", "cors": "^2.8.5" }

Dev Dependencies:

{ "@types/express": "^4.17.21", "@types/node": "^20.10.6", "nodemon": "^3.0.2", "ts-node": "^10.9.2", "typescript": "^5.3.3" }

Next Steps