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 parsingnanoid
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:
| Library | Length | URL-Safe | Secure | Size |
|---|---|---|---|---|
| nanoid | 6-21 | Yes | Yes | 130 bytes |
| uuid | 36 | No | Yes | 3KB |
| shortid | 7-14 | Yes | No | 8KB |
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 JSDocswagger-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.tsts-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 resourcesPOST- Create resourcesPUT- Update resourcesDELETE- 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();
});
});Code Quality Tools (Recommended)
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
Recommended IDE
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 18Production 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
- Architecture Overview - System design and components
- Data Models - Data structure details
- Development Setup - Start developing