Open source • AGPL-3.0 • In active development

A team chat you can read, run and host yourself.

LINK is a real-time messaging app — private chats, groups, files, voice notes and 1:1 calls — that runs on your own infrastructure. It's an independent project I build and maintain in the open: the code, the design decisions and the known limitations are all in the repository.

  • TypeScript end to end
  • Your data in your PostgreSQL
  • Runs with Docker Compose
  • Documented design decisions
Illustration of the interface: a group conversation with reactions, a voice note and a poll.
  • TypeScript
  • Node.js
  • Express
  • Socket.IO
  • PostgreSQL
  • Prisma
  • Next.js
  • React
  • WebRTC
  • Web Push
  • S3-compatible storage
  • Docker
  • Vitest

What can you do with LINK?

What works today, as it is in the code. The limitations are listed further down in Project status.

Real-time messaging

Private chats, groups and a personal "saved messages" chat. Replies, forwarding, editing and deleting, @mentions, reactions, typing indicators, and delivery and read receipts.

Socket.IO

Files and voice notes

Attach files and images, record voice notes or take a photo with the camera. Files are stored on local disk or in any S3-compatible service, where large uploads go in resumable parts.

Local disk or S3

Audio and video calls

One-to-one calls over WebRTC, peer to peer: the server relays the signaling and keeps the call history, but the media never goes through it. Includes ringtones, camera and microphone switching, and push notifications for incoming calls.

WebRTC • 1:1

Groups

Group admins and per-group rules for who can add or remove members, edit the group, delete it or leave it, on top of installation-wide defaults. Single or multiple-choice polls, and contact sharing.

Polls • group admins

Administration

An admin panel for global settings and storage, user accounts (create, reset passwords, deactivate), the session and password policy, message retention and an audit log of security-relevant actions.

Admin panel

Installable, in two languages

A Progressive Web App you can install on desktop and mobile, with Web Push notifications. The interface is in English and Spanish, with light and dark themes.

PWA

How is it built?

A TypeScript monorepo with two apps: an Express + Socket.IO API backed by PostgreSQL, and a Next.js client. Each backend module has its own README explaining its decisions.

Real time

Socket.IO with one room per conversation and a personal room per user. The handshake is authenticated with the session token, and joining a conversation room checks membership. Messages, receipts, typing indicators, reactions and call signaling share that channel.

backend/src/socket →

Calls

WebRTC with signaling (offer, answer, ICE candidates) relayed through Socket.IO. The backend tracks each call's state and writes it to the conversation history. NAT traversal currently relies on public STUN servers only, with no TURN.

backend/src/modules/calls →

Files

Two upload paths: small files go through the backend, large ones are sent in parts straight to S3-compatible storage with presigned URLs and can be resumed. Downloads use short-lived HMAC-signed URLs and are served with nosniff and a sandboxed CSP.

Large files design document →

Authentication

Local accounts by default: scrypt password hashing, HS256 session tokens that can be revoked per user, and an admin-defined session and password policy (length, expiry, history, lockout). Making external identity providers pluggable is on the roadmap.

Local auth design document →

Logs and audit trail

Structured JSON logs (pino) correlated per request, socket event and background job. A separate audit trail records security-relevant actions, with explicit privacy rules: never message content, never tokens.

Logging design document →

Tests and CI

Every behavior change ships with unit tests (Vitest, backend and frontend). CI runs them with coverage thresholds, builds both apps and the Docker images, and applies the migrations to an empty database to catch schema drift.

Testing design document →

Can I run it myself?

Yes. Docker Compose starts PostgreSQL, the backend and the frontend, and migrations run when the backend starts.

Terminal
git clone https://github.com/anderlfrias/link.git
cd link
cp .env.example .env
# Fill in POSTGRES_PASSWORD, LOCAL_AUTH_JWT_SECRET
# and the VAPID keys (the README shows how)
docker compose up -d --build
docker compose exec backend npm run auth:admin -- \
  create-admin --email you@example.com

Then open http://localhost:3000 and sign in with the temporary password the last command prints. You'll be asked to change it.

  • Requirements: Docker with Compose. Without Docker: Node.js 22.12+ or 24, and PostgreSQL.
  • Storage: local disk by default. S3-compatible storage is optional.
  • Today the secrets have to be generated by hand. A setup command that does it for you is planned.
Full installation guide

What's done and what isn't

LINK is usable today and still evolving. These are its real limitations, not a sales checklist.

Works today

  • Private chats, groups and saved messages
  • Files, images, voice notes and camera photos
  • 1:1 audio and video calls
  • Polls, reactions, mentions and replies
  • Admin panel, local accounts and audit log
  • PWA with push notifications
  • English and Spanish UI, light and dark themes

Known limitations

  • The backend runs as a single instance (no shared Socket.IO adapter yet)
  • Calls are 1:1 only and use public STUN servers, with no TURN, so they can fail behind strict NATs
  • No online/offline presence
  • In-chat search only covers messages already loaded
  • No end-to-end encryption
  • Files over 16 MiB need S3-compatible storage for now
  • Some texts are still Spanish-only (server errors, notifications)

Next steps

  • Pluggable identity providers (OIDC, LDAP…)
  • A setup command that generates the secrets
  • Large uploads without S3
  • A security review and hardening pass
  • Configurable STUN/TURN servers
  • Complete the English translation
  • End-to-end tests

Next steps are intentions, not commitments. Every change is recorded in the CHANGELOG.

Frequently asked questions

Can I use LINK in my organization?

Yes. LINK is licensed under the GNU AGPL v3.0. You can use it, modify it and run it for your team. If you modify it and make it available to other people over a network, you have to offer them the source code of your version under the same license.

Does it depend on external services?

Nothing you have to sign up for. Messages live in your PostgreSQL and files on your disk or your own S3-compatible storage. A few things do reach outside: calls use Google's public STUN servers to set up the peer-to-peer connection, push notifications go through each browser vendor's push service (as with any web app), and GIF search through GIPHY is optional and off by default.

Is there a mobile app?

Not a native one. LINK is a Progressive Web App: it works in modern browsers and can be installed on desktop and mobile, with push notifications where the browser supports them.

Who is behind LINK?

LINK is an independent project built and maintained by Anderson Frias. It started as the internal chat of a real team, where it's still used every day, and is now developed in the open.

How can I contribute or report a problem?

Start with CONTRIBUTING.md. Bugs and proposals go in GitHub issues. Report vulnerabilities privately as explained in SECURITY.md, not in a public issue.

The code is on GitHub

Read it, run it, open an issue or send a pull request.