Self-hosted service
shortlink-org/shortlink avatar
shortlink-org/shortlink

ShortLink: a microservices reference you can read end to end

Shortlink service (Microservice example) ⭐️ Star the repo if you like it!

767 stars37 forksTypeScriptMIT

At a glance

What is it?
ShortLink is an open source educational project that demonstrates microservices architecture with a working short link service, split into bounded contexts with an event store, a message queue and a Kubernetes deployment path. Its value is as a reference implementation to read, and its release history shows the gap between an active repository and a released version.
Who is it for?
Adopt ShortLink as a reference to read and to fork when you want a worked example of bounded contexts, event sourcing and GitOps deployment rather than as a service to run in production. Do not expect a maintained product from it, because the most recent tagged release is 0.19.0 from 2024-09-29 even though the repository was pushed to on 2026-10-03.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 21 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A teaching project with a working system behind it

ShortLink is described as an open source educational project that provides a user interface and respects GDPR, and the stated goal is to demonstrate the practical application of microservices architecture. The homepage is shortlink.best, and the application itself is a link shortener with the operational furniture of a serious system behind it.

That combination is the point. A diagram in a slide deck teaches a pattern; a repository where the pattern is running carries the parts that are hard to get right, the message queue topics, the store adapters, the migrations, the Helm chart, the ingress and the CI. The topic list on the repository shows the range the project covers, including DDD and event sourcing, Kafka and a message queue, layered architecture, code generation, a CSI driver, Helm charts, ArgoCD and GitOps, and a set of best-practice labels.

The metadata lists TypeScript as the primary language, which fits the interface, while the topics and the build files point at Go for the services, with go.mk among the included makefiles and a Go package on the Go module proxy.

The maturity signals in the README are the usual ones for a project that wants to be taken seriously: a CII Best Practices badge, an SLSA badge, coverage reporting through codecov, a FOSSA licence report, DeepSource analysis, a Go Report Card entry and an Artifact Hub listing for the Helm chart.

Bounded contexts as the organising unit

The repository root shows the shape of the design. There is a boundaries/ directory, which is where the bounded contexts of the domain live, alongside ops/ for the operational code such as the deployment and infrastructure, poc/ for proof of concept work, and docs/ for the documentation. A docker-compose.yaml at the root, an .env.example, a Makefile and a set of files for the various deployment targets sit alongside them.

The release history shows the boundaries being carved out over time. The 0.18.0 release is titled Shop boundary, and the 0.19.0 release is titled Add currency service, so the version notes record the domain decomposition as it happened rather than presenting a finished design.

The README states that each boundary context and service has its own architecture decision record, with the main decisions indexed in docs/ADR and the operational decisions in ops/docs/ADR. An ADR is described in the README as a document that captures an important architecture decision along with its context and consequences, and the project links to a well known description of the format.

That is the part of the repository that has the longest value for a reader. A boundary directory tells you what the split is, and the ADR for that boundary tells you why it was split that way, what the alternatives were and what the consequences are. In most reference code you get the first and not the second.

The storage layer as a contract in environment variables

Persistence is the part of the system that most often reveals whether an architecture is real. In ShortLink the store is chosen by configuration rather than by code, and the .env.example file is the contract.

The selection line lists the available backends and the default:

bash
STORE_TYPE=ram

The comment above it names the options, which are postgres, mongo, redis, dgraph, sqlite, leveldb, badger and ram, and states that the default is ram. That default is a good sign for a teaching project, since a reader can start without a database and swap in one later without touching the code.

The rest of the file gives the per-backend settings. Badger stores under /tmp/links.badger, LevelDB under /tmp/links.db, Dgraph connects to localhost:9080, MongoDB uses a connection string with a shortlink user and password pointing at a local instance, and the Postgres section follows. There is also a write mode setting with two enumerated values, zero for single write and one for batch write, and a default of zero.

The file also shows the separation between the identity service and the application services. A Kratos API block sets AUTH_URI to a local address on port 4433, which means authentication is a separate service that the others call, the standard arrangement for a microservice split where identity outlives any one bounded context.

Local networks, IPv6 and the compose file

The docker-compose.yaml in the repository is small, and what it does is worth reading closely. It defines one network called simple, whose name comes from the DOCKER_NETWORK environment variable, on the bridge driver with IPv6 enabled. The IPAM section pins two subnets, 10.5.0.0/16 with a gateway at 10.5.0.1 for IPv4 and 2001:0DB8::/112 with a gateway at 2001:0DB8::1 for IPv6:

yaml
    ipam:
      driver: default
      config:
        - subnet: 10.5.0.0/16
          gateway: 10.5.0.1
        - subnet: 2001:0DB8::/112
          gateway: 2001:0DB8::1

Pinning the subnets is what lets a container reach a peer by a predictable address, which matters for a service mesh or for a message broker that hands out addresses, and the dual stack is consistent with the project running the Kafka and ingress pieces that expect a stable network layout.

A named volume called database is declared at the end, which is where stateful data survives a container replacement. The rest of the local stack is not in this file, which is a clue about how the project is structured: the compose file is one tool among several, and the Makefile drives the rest.

Secrets are handled separately, with a .sops.yaml at the root for encrypted values and a .env.example that contains only defaults and placeholders, so the example file can be committed without leaking a credential.

A Makefile assembled from included parts

The root Makefile is short because it is an index rather than a build script. It sets SELF_DIR to the directory of the Makefile itself and then includes a list of files from the ops/Makefile directory:

make
include $(SELF_DIR)/ops/Makefile/common.mk
include $(SELF_DIR)/ops/Makefile/docs.mk
include $(SELF_DIR)/ops/Makefile/cert.mk
include $(SELF_DIR)/ops/Makefile/cli.mk
include $(SELF_DIR)/ops/Makefile/vagrant.mk
include $(SELF_DIR)/ops/Makefile/ansible.mk
include $(SELF_DIR)/ops/Makefile/terraform.mk
include $(SELF_DIR)/ops/Makefile/dev.mk
include $(SELF_DIR)/ops/Makefile/go.mk
include $(SELF_DIR)/ops/Makefile/git.mk
include $(SELF_DIR)/ops/Makefile/k8s/k8s.mk

The list is a table of contents for the operational surface of the project. There is a target set for Go builds, one for Git, one for Kubernetes that includes a nested k8s.mk, and separate ones for certificates, the command line interface, documentation, Vagrant, Ansible and Terraform.

The two deployment tools, Ansible and Terraform, sitting side by side is the clearest sign of the reference nature of the project. A real service picks one infrastructure approach and commits to it; a teaching project shows both so that a reader can see how the same declarative outcome is expressed in two different vocabularies.

The remaining root files are the governance layer of a project that expects contributions: CONTRIBUTING.md with a getting started section, CODE_OF_CONDUCT.md, GOVERNANCE.md, SECURITY.md, a CHANGELOG, a ROADMAP, CITATION.cff for academic citation, AGENTS.md and an ADOPTERS.md that points adopters at the right entry point. The .golangci.yml, the .pre-commit-config.yaml and the .editorconfig are the local quality gates, and .clusterfuzzlite/ points at fuzzing support for the native code paths.

Licence, release cadence and what a learner inherits

The repository carries an MIT licence, and the README attaches an important warning to it. The project includes dependencies licensed under the GNU Lesser General Public License, users must comply with the LGPL terms when using or modifying those dependencies, and the detailed per-library information is in the FOSSA report the README links. In other words, the repository's own licence does not describe the terms of what you get when you build it, and for a project whose purpose is to be copied, that distinction is the first thing to read.

The release history is where the caution is needed. The most recent tagged versions are 0.17.0 from 2024-07-25, 0.18.0 from 2024-09-07 and 0.19.0 from 2024-09-29, while the last push to the repository was on 2026-10-03. More than two years of commits have landed on the default branch without a new release tag, which means the tagged version and the current state of the code are very different things, and the Helm chart, the images and the documentation that correspond to a given tag are not the ones you get by cloning main.

That is acceptable for an educational repository, where the value is in reading the current code, and it is a problem for anyone who wants to depend on a released artefact. A reader should treat the main branch as the canonical example and the tags as historical markers.

What a learner inherits is still substantial. A service split along domain boundaries, each with its own decision record, a storage abstraction with eight backends, an event-driven backbone with Kafka in the topic list, GitOps deployment through ArgoCD, and the operational tooling for the common environments.

Editorial conclusion

Adopt ShortLink as a reference to read and to fork when you want a worked example of bounded contexts, event sourcing and GitOps deployment rather than as a service to run in production. Do not expect a maintained product from it, because the most recent tagged release is 0.19.0 from 2024-09-29 even though the repository was pushed to on 2026-10-03. Before you copy any of it, read the ADR index in docs/ADR, and check the LGPL notice in the README, since the project ships dependencies whose terms differ from the MIT licence of the repository itself.

Frequently asked questions

What is the ShortLink project for?

The README describes it as an open source educational project whose goal is to demonstrate the practical application of microservices architecture, with a user interface and attention to GDPR.

Which storage backends does ShortLink support?

The .env.example file lists postgres, mongo, redis, dgraph, sqlite, leveldb, badger and ram, selected with the STORE_TYPE variable, and ram is the default. Each backend has its own connection or path setting in the same file.

How is the ShortLink codebase organised?

The repository has a boundaries directory for the bounded contexts, an ops directory for operational code and infrastructure, a poc directory, and docs. Each boundary context and service has its own architecture decision record, indexed in docs/ADR and ops/docs/ADR.

What licence does ShortLink use and are there exceptions?

The repository is MIT licensed, but the README warns that the project includes dependencies licensed under the LGPL, which users must comply with, and points to the FOSSA report for the per-library details.

When was the last ShortLink release?

The most recent tags are 0.17.0 from 2024-07-25, 0.18.0 from 2024-09-07 and 0.19.0 from 2024-09-29, while the last push to the repository was on 2026-10-03, so the default branch is well ahead of the last release.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. shortlink-org/shortlink on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/shortlink-org-shortlink.svg)](https://hysenlabs.com/projects/shortlink-org-shortlink)

Was this useful?