A fast and highly customizable Linktree alternative, built with Next.js. Forked from vijay verma's nxtlnk and made my own improvements. Made sincerely for people who love making their own link-in-bio page.
This repository is hosted on Codeberg and mirrored on GitHub and GitLab.
See the site in action: https://jar.tf
- Group your links by categories
- Manage everything directly from data objects in
data/ - Dark/light mode, of course lol
- Easily handle redirects and short URLs
- Out-of-the-box metadata support configured via
next-seo - Modular and reusable component styling
- Framework: Next.js (React)
- Styling:
styled-components - SEO:
next-seo - Theming:
next-themes
Ensure you have Node.js and pnpm (preferred, though npm or any other is fine) installed.
-
Clone this repository, or yours if you’ve already deployed it:
git clone https://codeberg.org/jartf/links.git cd links -
Install the dependencies:
pnpm install
-
Start the development server:
pnpm dev
-
Open http://localhost:3000 or whatever URL is displayed in the terminal.
All configurations live in data/ and root. If you're only changing the profile info and links, these are the only files you'll ever need to touch :D
- Profile:
data/BioData.jscontains the site's name, avatar, bio text, the whole nine yards of information. - Links:
data/LinksData.jscontains displayed links. You can assign different link types to organize them into sections. For my configuration, sectiontopis the mini top bar right below the site info for social links. - Shortlinks:
data/ShortLinks.jscontains URL redirects to other sites and allows the site to double as a custom link shortener. - SEO details:
next-seo.config.jsis the site’s meta tags and OpenGraph objects configuration.
If you want to understand how the code works and/or customize it further, here’s a quick overview of the implementation:
- Most of the UI is built with
components/.WebLinks.jsis the core UI. It parsesBioData.jsandLinksData.jsto render the profile and links.Layout.jsis the wrapper component for all pages. It contains the floating<ThemeToggle />button for theme switching.Seo.jsinjects metadata tags onto the page.
pages/index.jsis the main page but really only imports and displays the<Seo />and<WebLinks />components. Nothing too fancy there.- Styling (
styles/):theme.config.jscontains the color variables for dark and light themes.GlobalStyle.jscontains typography and default styles.- Dark mode triggers via
next-themesand is configured atpages/_app.js.
There are two types of shortlinks:
- A "temporary" shortlink is a simple redirect from a path on the site to an external URL.
- You can configure these in
data/ShortLinks.jsand they'll be handled by the catch-all route inpages/[...slug].js. - Alternatively, you can add them directly in the redirects array of
next.config.js, but it can get messy fast in the long run.
- You can configure these in
- A "permanent" shortlink (aka a permashortlink) is a redirect configured in the Next.js middleware (
proxy.js). It formats links to point to my blog based on 4 URL patterns, in the following order:/b/YYMMDDHHMM: Checks for a 10-digit number in the format of year-month-day-hour-minute, and redirects tohttps://jarema.me/blog/20YY/MM/DD/hh/mm/./b/AAATTT: This is an algorithmic shortlink with 6 alphanumeric characters, encoded in Base36 to point to a blog datetime.AAA= Base36 days since 2000-01-01, covers dates from 2000 to end of 2099.TTT= Base36 minutes since midnight, range 0-1439.- Example:
https://jar.tf/b/7eb0nrdecodes tohttps://jarema.me/blog/2026/04/01/14/15/(case-insensitive). Try it out, I've hyperlinked that one shortlink :3
/b/YYMM/slug: Extracts the date and slug, and redirects tohttps://jarema.me/blog/20YY/MM/slug/./b/slug: Redirects tohttps://jarema.me/blog/slug/.
More about the algorithmic shortlink format in an upcoming blog post :D
The next.config.js uses these HTTP security headers to try to minimise attack surface:
- Content-Security-Policy: Default is nothing running with
default-src 'none', inline scripts are scoped with sha256 checksums. I had to temporarily allow'unsafe-eval'in development because of React, but it's not in production. Styles areunsafe-inlinebecause ofstyled-componentssadly. - Permissions-Policy: Disables FLoC/topics tracking, camera, microphone, geolocation, and USB.
- Strict-Transport-Security: 1-year max age with subdomains included.
- Cross-origin policies: Implements
require-corpembedder policy,same-origin-allow-popupsopener policy, andsame-siteresource policy. - Other protections:
Referrer-Policyis set tostrict-originX-Frame-OptionsisDENYX-Content-Type-OptionsisnosniffX-XSS-Protectionis0, not1; mode=blockbecause browsers have deprecated the header and now prefer to rely on Content-Security-Policy for XSS protection, and the old header can cause issues.Sec-GPC(Global Privacy Control) is1, not that I track anything but hey, might as well respect it.Origin-Agent-Clusteris set to?1to enable origin isolation and mitigate memory attacks.
Issues, feature requests, pull requests, or even just comments are all welcome! Feel free to check the issues page on Codeberg.
Thanks to vijay verma (@realvjy) for creating the original nxt-lnk.
A huge thanks to the maintainers of the open-source projects this site relies on:
This project is licensed under the MIT License.