Home
Softono

Node Url Shortener

Open source MIT JavaScript
32
Stars
29
Forks
0
Issues
1
Watchers
2 months
Last Commit

 About Node Url Shortener

URL Shortener in Base58 using Node.js, Express, Sequelize, Mocha and Bootstrap

Platforms

Web Self-hosted

Languages

JavaScript

Links

Need Help Installing Node Url Shortener?

We provide expert installation service for this software. Our team will install, configure, and secure Node Url Shortener on your server. plans start at just $30.

Node Url Shortener

View on GitHub

Node URL Shortener

Stack

File structure

node-url-shortener/
│
├── api/
│   ├── controllers/
│   │   └── UrlController.js
│   ├── models/
│   │   └── Url.js
│   └── helpers/
│       └── base58.js
│
├── config/
│   ├── env/
│   │   ├── development.js
│   │   ├── index.js
│   │   ├── production.js
│   │   └── test.js
│   ├── middleware/
│   │   └── errorHandler.js
│   ├── routes/
│   │   ├── index.js
│   │   └── url.js
│   ├── database.js          * Sequelize CLI (migrations)
│   ├── express.js
│   └── sequelize.js
│
├── migrations/              * Sequelize migrations
├── seeders/
├── view/
│   ├── css/
│   ├── javascript/
│   │   └── shorten.js
│   └── index.html
│
├── test/
│   └── url.test.js
│
├── .eslintrc.json
├── .gitignore
├── .sequelizerc
├── index.js                 * Application entry point
├── LICENSE
├── package.json
├── package-lock.json
└── README.md

Screenshot

App screenshot

Introduction

What is a URL shortener?

URL shortening turns a long URL into a shorter one that redirects to the original. The short link is easier to share and remember.

How does this project implement it?

The database stores each URL with an auto-increment numeric id. The short code in the path is that id encoded in Base58 (alphanumeric, excluding ambiguous characters like 0, O, I, l). When someone opens /:encodedId, the server decodes it to id, loads the row, and redirects to longUrl.

There is a unique index on longUrl so the same URL is never stored twice; concurrent POST requests are handled with findOrCreate and a fallback if a uniqueness race occurs.

Requirements

  • Node.js 18 or newer (LTS recommended)
  • MySQL 5.7+ or 8.x

Environment variables

Variable Description Default (from env files)
NODE_ENV development, test, or production development
PORT HTTP port 3000
DB_HOST MySQL host localhost
DB_PORT MySQL port 3306
DB_NAME Database name shortener_dev / shortener_test / shortener by environment
DB_USER MySQL user root
DB_PASSWORD MySQL password root (override in production)
PUBLIC_URL or BASE_URL Public base URL for short links (no trailing slash), e.g. https://short.example.com If unset, derived from the incoming request (req.protocol and Host)
TRUST_PROXY Set to true or 1 if the app sits behind a reverse proxy so X-Forwarded-* is honored unset

Copy values into a .env file or your host’s secret manager. The .env file is gitignored; do not commit real passwords.

Installation

  1. Clone the repository:
git clone https://github.com/murraco/node-url-shortener.git
cd node-url-shortener
  1. Install dependencies:
npm install
  1. Configure the database using the variables above (optional .env or shell exports). The files under config/env/ only supply defaults and read from process.env.

Database setup

With Docker (MySQL 8)

docker run -d --name mysql-shortener \
  -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD=root \
  mysql:8

Create the databases (adjust user/password if needed):

docker exec -it mysql-shortener mysql -uroot -proot -e "
  CREATE DATABASE IF NOT EXISTS shortener_dev;
  CREATE DATABASE IF NOT EXISTS shortener_test;
  CREATE DATABASE IF NOT EXISTS shortener;
"

Migrations (production and clean setups)

After MySQL is running and credentials match config/env (or your env vars), apply the schema:

npm run migrate

In development only, the app also runs sequelize.sync() on startup so tables are created if missing. Production does not sync on startup; run migrations before deploying.

Running the app

  • Production-style: npm start → runs node index.js (connects to DB, no sync when NODE_ENV=production).
  • Development with reload: npm run devnodemon index.js.

Then open http://localhost:3000 (or your PORT).

API

GET /api-status

Health check. Response: { "status": "ok" }

POST /api/shorten

Creates or returns an existing short link for a URL.

  • Body (JSON): { "url": "https://example.com/path" }
  • Success: 201{ "shortUrl": "<public-base>/<base58-id>" }
  • Errors: 400{ "error": "..." } for missing/invalid URL or non-http(s) scheme
  • Server errors: 500{ "error": "Internal server error" }

Register new single-segment routes before /:encodedId in the router so they are not treated as short codes.

GET /:encodedId

Redirects (302) to the stored URL, or to the site root if the code is unknown.

Testing

Tests use NODE_ENV=test (see test/url.test.js), the shortener_test database (unless overridden with DB_NAME), and Url.sync({ force: true }) in a before hook to reset the table.

Requirements: MySQL running and the test database created.

npm test

npm audit was run after dependency updates; a few advisories may remain in transitive dev dependencies (for example Mocha). Re-run npm audit periodically.

Contributing

Buy me a coffee

ko-fi