by Omar V.

Self-hostable URL shortener supporting custom domains, link statistics, user management, and multi-database backends. Built for developers who need a full-featured, configurable link management platform.
Kutt is a self-hosted URL shortener backend built on Express, Knex, and Bull. It exposes a RESTful API for creating, managing, and tracking shortened links with support for custom domains, user authentication, and visit statistics. The typical buyer is a Node.js developer embedding a production-grade link-shortening service into an existing application or deploying it standalone.
.github/ - CI/CD workflows for Docker image buildsdocs/ - API documentation generator scriptsserver/ - Core application: handlers, models, queries, queues, routes, mail, and migrationsstatic/ - Static assets served by the Express appLICENSE - MIT licenseREADME.md - Project overview and setup instructionsdocker-compose.yml - Default SQLite-based Docker setupdocker-compose.postgres.yml - Postgres + Redis Docker setupdocker-compose.mariadb.yml - MariaDB + Redis Docker setupdocker-compose.sqlite-redis.yml - SQLite + Redis Docker setupjsconfig.json - JavaScript project configurationknexfile.js - Knex database configuration for migrationspackage.json - Dependencies and npm scriptsnpm install bcryptjs better-sqlite3 bull cookie-parser cookie-session cors date-fns dotenv envalid express express-rate-limit express-validator geoip-lite hbs helmet ioredis isbot jsonwebtoken knex ms mysql2 nanoid nodemailer openid-client passport
better-sqlite3 requires a native build step. Ensure you have Python and a C++ compiler available:
npm install --build-from-source better-sqlite3
# On Debian/Ubuntu: apt-get install -y python3 make g++
# On macOS: xcode-select --install
Copy the source/ directory into your project root, e.g. as ./kutt/.
Install dependencies from the root of your project:
npm install
Initialize the database (runs all Knex migrations):
node -e "require('./kutt/knexfile')" # verify config loads
npx knex migrate:latest --knexfile ./kutt/knexfile.js
Spin up an isolated sandbox and run it server-side — no local setup.
Tetrees AI Review of this version
This Express backend / api completed archive review with strong static results. Structure, dependency manifests, documentation, functional source, and common risk patterns were checked by the Tetrees verification pipeline; runtime phases are stated separately.
Deterministic AVCP artifact review
Pipeline avcp-2026-08-04.1 · SHA-256 5f12eef5a9bf9cdc…
This version-scoped review deterministically inspects the submitted archive for structure, dependencies, documentation, functional source, and common malicious or high-risk signals. Build and test phases are reported as passed only after an isolated sandbox audition. It is not a guarantee of perfect security.
Reviewed Aug 4, 2026
Push this product straight into your AI IDE, web builder or cloud IDE.
Connect Tetrees to a compatible AI IDE, list products you own, and request the verified ZIP without exposing seller upload controls.
No reviews yet.
Sign in to join the discussion
Loading discussion…
Create a .env file (or export environment variables). Only JWT_SECRET is required in production:
JWT_SECRET=your-secret-here
# Optional but common:
DB_CLIENT=sqlite3 # or pg, mysql2
DB_FILENAME=./kutt.sqlite # for sqlite3
REDIS_ENABLED=false
PORT=3000
Start the server:
node ./kutt/server/server.js
# or for development:
npm run dev
If embedding into an existing Express app, require the routes module and mount it:
const routes = require("./kutt/server/routes");
app.use("/", routes);
import queries from "./kutt/server/queries/index";
// queries.domain - domain-related DB operations
// queries.host - host-related DB operations
// queries.link - link CRUD and lookup
// queries.user - user CRUD and lookup
// queries.visit - visit recording and stats
The queries object is the primary data-access layer. Use queries.link to create or retrieve shortened links, queries.user for account management, and queries.visit for analytics. Each sub-namespace wraps Knex query builders for the corresponding table.
server/models/index.js)const models = require("./kutt/server/models/index");
// Spreads: domain.model, host.model, ip.model, link.model, user.model, visit.model
Models define the Knex table schemas and seed/factory helpers used internally by queries and migrations. Reference them when writing custom queries or extending the schema.
server/queues/index.js)const { visit } = require("./kutt/server/queues/index");
// visit: Bull queue for async visit recording
The visit queue is a Bull job queue. Enqueue a job whenever a link is visited to record analytics asynchronously without blocking the redirect response. Backed by Redis when REDIS_ENABLED=true, otherwise falls back to in-process processing.
server/mail/index.js)const mail = require("./kutt/server/mail/index");
// Re-exports ./mail.js: functions for sending verification, reset, and change-email messages
Use mail to trigger transactional emails (account verification, password reset, email change). Requires SMTP configuration via environment variables (MAIL_HOST, MAIL_PORT, MAIL_USER, MAIL_PASSWORD).
Drop Kutt's route tree under a sub-path in your existing Express application, sharing the same process.
import express from "express";
import cookieParser from "cookie-parser";
import helmet from "helmet";
const app = express();
// Kutt expects these middleware upstream
app.use(helmet());
app.use(cookieParser());
app.use(express.json());
// Mount Kutt routes
const kuttRoutes = require("./kutt/server/routes/index");
app.use("/k", kuttRoutes);
app.listen(3000, () => {
console.log("Server running on port 3000");
});
When you handle a custom redirect outside Kutt's own handlers, enqueue a visit job so analytics are still recorded.
import express from "express";
const { visit: visitQueue } = require("./kutt/server/queues/index");
const queries = require("./kutt/server/queries/index");
const router = express.Router();
router.get("/r/:slug", async (req, res) => {
const link = await queries.link.find({ address: req.params.slug });
if (!link) return res.status(404).send("Not found");
// Enqueue visit for async processing - do not await
visitQueue.add({
linkId: link.id,
referrer: req.headers.referer || "",
ip: req.ip,
headers: req.headers,
});
return res.redirect(301, link.target);
});
export default router;
Trigger a reset email from your own auth controller using Kutt's mail module directly.
const mail = require("./kutt/server/mail/index");
const queries = require("./kutt/server/queries/index");
async function requestPasswordReset(email: string): Promise<void> {
const user = await queries.user.find({ email });
if (!user) return; // silently ignore unknown addresses
const resetToken = generateSecureToken(); // your own token utility
await queries.user.update({ id: user.id, reset_password_token: resetToken });
await mail.sendResetEmail({
to: email,
resetLink: `https://yourdomain.com/reset?token=${resetToken}`,
});
}
server/server.js - Entry point; creates and starts the Express server.server/env.js - Validates and exports typed environment variables via envalid.server/knex.js - Initializes and exports the Knex database connection singleton.server/redis.js - Initializes and exports the ioredis client; no-op when Redis is disabled.server/passport.js - Configures Passport.js strategies (JWT, OIDC).server/cron.js - Registers cron jobs (e.g., expiring links cleanup).server/consts.js - Shared application-wide constants.server/handlers/ - Express request handlers for auth, domains, links, users, renders, and validation.server/routes/ - Route definitions wiring HTTP verbs to handlers; index.js is the root export.server/models/ - Knex table schema definitions for all entities.server/queries/ - Database query functions grouped by entity; exported as a single namespace object.server/queues/ - Bull queue definitions; visit queue for async analytics.server/migrations/ - Ordered Knex migration files for schema versioning.server/mail/ - Nodemailer-based email utilities and HTML templates.server/views/ - Handlebars templates for server-rendered pages.static/ - Public static assets (images, CSS, JS) served directly by Express.knexfile.js - Knex CLI configuration; reads env vars for DB client and connection.docs/api/ - Scripts to generate the public API documentation site.JWT_SECRET not set in production: The app will fail to sign tokens. Always set JWT_SECRET via env or .env file before starting in production.better-sqlite3 native build fails: Ensure python3, make, and g++ are installed; on CI, add apt-get install -y python3 make g++ before npm install.REDIS_ENABLED=true: Either start a Redis instance or set REDIS_ENABLED=false; the app does not gracefully fall back automatically.npx knex migrate:latest --knexfile knexfile.js before starting; missing tables cause immediate 500 errors.geoip-lite database not downloaded: Run node node_modules/geoip-lite/scripts/updatedb.js after install if geographic visit data is needed; the module ships without the data files.server.js calls app.listen internally; when mounting only routes into your own app, require server/routes/index directly and do not call server.js.I have purchased the "Kutt URL Shortener (Backend)" AVCP block. The source is
in ./kutt/ (copied from source/). I also have USAGE.md open for reference.
Upstream package: user@example.com
My project is a Node.js/TypeScript Express application. Please help me
integrate Kutt step by step:
1. Read USAGE.md and the file layout in ./kutt/server/ to understand the
exported modules (routes, queries, queues, mail, models).
2. Mount ./kutt/server/routes/index.js under /links in my existing app.js.
3. Wire the required middleware (helmet, cookieParser, express.json) before
the mounted routes.
4. Show me how to use queries.link and queries.user from
./kutt/server/queries/index.js in a custom controller.
5. Show me how to enqueue a visit using the Bull queue exported from
./kutt/server/queues/index.js.
6. Generate the .env entries I need, referencing ./kutt/server/env.js for
the full list of accepted variables.
7. Run the migrations using knexfile.js and confirm the schema is ready.
Do not invent any API surface; only use exports documented in USAGE.md and
visible in the source files.
Kutt is released under the MIT License. See source/LICENSE for the full text.
Upstream repository and package: kutt on npm / thedevs-network/kutt on GitHub.
This product’s unique contribution is clean room implementation of valuable code block into AVCP compatible standard.
The full install guide and integration prompts unlock after purchase.
Automation, Utilities & Developer Tools
Free